From 591270bb05dd512a18de03a528ff24fb07b7a75e Mon Sep 17 00:00:00 2001 From: VahidN Date: Mon, 11 Jun 2018 13:31:26 +0430 Subject: [PATCH] Added QRCode.Apache.License sample --- .../QRCode.Apache.License/Issue26.cs | 64 ++ .../QRCode.Apache.License/qrcode/BitArray.cs | 177 ++++++ .../QRCode.Apache.License/qrcode/BitMatrix.cs | 192 ++++++ .../QRCode.Apache.License/qrcode/BitVector.cs | 160 +++++ .../QRCode.Apache.License/qrcode/BlockPair.cs | 39 ++ .../QRCode.Apache.License/qrcode/ByteArray.cs | 97 +++ .../qrcode/ByteMatrix.cs | 98 +++ .../qrcode/CharacterSetECI.cs | 98 +++ .../qrcode/EncodeHintType.cs | 40 ++ .../QRCode.Apache.License/qrcode/Encoder.cs | 570 +++++++++++++++++ .../qrcode/ErrorCorrectionLevel.cs | 84 +++ .../qrcode/FormatInformation.cs | 175 ++++++ .../QRCode.Apache.License/qrcode/GF256.cs | 143 +++++ .../QRCode.Apache.License/qrcode/GF256Poly.cs | 271 ++++++++ .../QRCode.Apache.License/qrcode/MaskUtil.cs | 220 +++++++ .../qrcode/MatrixUtil.cs | 520 ++++++++++++++++ .../QRCode.Apache.License/qrcode/Mode.cs | 115 ++++ .../QRCode.Apache.License/qrcode/QRCode.cs | 240 +++++++ .../qrcode/QRCodeWriter.cs | 134 ++++ .../qrcode/ReedSolomonEncoder.cs | 75 +++ .../qrcode/ReedSolomonException.cs | 35 ++ .../QRCode.Apache.License/qrcode/Version.cs | 585 ++++++++++++++++++ .../qrcode/WriterException.cs | 39 ++ 23 files changed, 4171 insertions(+) create mode 100644 src/iTextSharp.LGPLv2.Core.FunctionalTests/QRCode.Apache.License/Issue26.cs create mode 100644 src/iTextSharp.LGPLv2.Core.FunctionalTests/QRCode.Apache.License/qrcode/BitArray.cs create mode 100644 src/iTextSharp.LGPLv2.Core.FunctionalTests/QRCode.Apache.License/qrcode/BitMatrix.cs create mode 100644 src/iTextSharp.LGPLv2.Core.FunctionalTests/QRCode.Apache.License/qrcode/BitVector.cs create mode 100644 src/iTextSharp.LGPLv2.Core.FunctionalTests/QRCode.Apache.License/qrcode/BlockPair.cs create mode 100644 src/iTextSharp.LGPLv2.Core.FunctionalTests/QRCode.Apache.License/qrcode/ByteArray.cs create mode 100644 src/iTextSharp.LGPLv2.Core.FunctionalTests/QRCode.Apache.License/qrcode/ByteMatrix.cs create mode 100644 src/iTextSharp.LGPLv2.Core.FunctionalTests/QRCode.Apache.License/qrcode/CharacterSetECI.cs create mode 100644 src/iTextSharp.LGPLv2.Core.FunctionalTests/QRCode.Apache.License/qrcode/EncodeHintType.cs create mode 100644 src/iTextSharp.LGPLv2.Core.FunctionalTests/QRCode.Apache.License/qrcode/Encoder.cs create mode 100644 src/iTextSharp.LGPLv2.Core.FunctionalTests/QRCode.Apache.License/qrcode/ErrorCorrectionLevel.cs create mode 100644 src/iTextSharp.LGPLv2.Core.FunctionalTests/QRCode.Apache.License/qrcode/FormatInformation.cs create mode 100644 src/iTextSharp.LGPLv2.Core.FunctionalTests/QRCode.Apache.License/qrcode/GF256.cs create mode 100644 src/iTextSharp.LGPLv2.Core.FunctionalTests/QRCode.Apache.License/qrcode/GF256Poly.cs create mode 100644 src/iTextSharp.LGPLv2.Core.FunctionalTests/QRCode.Apache.License/qrcode/MaskUtil.cs create mode 100644 src/iTextSharp.LGPLv2.Core.FunctionalTests/QRCode.Apache.License/qrcode/MatrixUtil.cs create mode 100644 src/iTextSharp.LGPLv2.Core.FunctionalTests/QRCode.Apache.License/qrcode/Mode.cs create mode 100644 src/iTextSharp.LGPLv2.Core.FunctionalTests/QRCode.Apache.License/qrcode/QRCode.cs create mode 100644 src/iTextSharp.LGPLv2.Core.FunctionalTests/QRCode.Apache.License/qrcode/QRCodeWriter.cs create mode 100644 src/iTextSharp.LGPLv2.Core.FunctionalTests/QRCode.Apache.License/qrcode/ReedSolomonEncoder.cs create mode 100644 src/iTextSharp.LGPLv2.Core.FunctionalTests/QRCode.Apache.License/qrcode/ReedSolomonException.cs create mode 100644 src/iTextSharp.LGPLv2.Core.FunctionalTests/QRCode.Apache.License/qrcode/Version.cs create mode 100644 src/iTextSharp.LGPLv2.Core.FunctionalTests/QRCode.Apache.License/qrcode/WriterException.cs diff --git a/src/iTextSharp.LGPLv2.Core.FunctionalTests/QRCode.Apache.License/Issue26.cs b/src/iTextSharp.LGPLv2.Core.FunctionalTests/QRCode.Apache.License/Issue26.cs new file mode 100644 index 0000000..00ce5d2 --- /dev/null +++ b/src/iTextSharp.LGPLv2.Core.FunctionalTests/QRCode.Apache.License/Issue26.cs @@ -0,0 +1,64 @@ +using System.IO; +using iTextSharp.text; +using iTextSharp.text.pdf; +using iTextSharp.text.pdf.codec; +using iTextSharp.text.pdf.qrcode; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace iTextSharp.LGPLv2.Core.FunctionalTests.Issues +{ + /// + /// https://github.com/VahidN/iTextSharp.LGPLv2.Core/issues/26 + /// + [TestClass] + public class Issue26 + { + [TestMethod] + public void Verify_Issue26_CanBe_Processed() + { + var pdfFilePath = TestUtils.GetOutputFileName(); + var stream = new FileStream(pdfFilePath, FileMode.Create); + + var document = new Document(); + PdfWriter.GetInstance(document, stream); + document.AddAuthor(TestUtils.Author); + document.Open(); + Image qrcodeImage = CreateQrCodeImage("This is a text ..."); + + //qrcodeImage.SetAbsolutePosition(10, 500); + qrcodeImage.ScalePercent(200); + document.Add(qrcodeImage); + + document.Close(); + stream.Dispose(); + + TestUtils.VerifyPdfFileIsReadable(pdfFilePath); + } + + private static Image CreateQrCodeImage(string content) + { + var qrCodeWriter = new QRCodeWriter(); + var byteMatrix = qrCodeWriter.Encode(content, 1, 1, null); + var width = byteMatrix.GetWidth(); + var height = byteMatrix.GetHeight(); + var stride = (width + 7) / 8; + var bitMatrix = new byte[stride * height]; + var byteMatrixArray = byteMatrix.GetArray(); + for (int y = 0; y < height; ++y) + { + var line = byteMatrixArray[y]; + for (var x = 0; x < width; ++x) + { + if (line[x] != 0) + { + int offset = stride * y + x / 8; + bitMatrix[offset] |= (byte)(0x80 >> (x % 8)); + } + } + } + var encodedImage = Ccittg4Encoder.Compress(bitMatrix, byteMatrix.GetWidth(), byteMatrix.GetHeight()); + var qrcodeImage = Image.GetInstance(byteMatrix.GetWidth(), byteMatrix.GetHeight(), false, Image.CCITTG4, Image.CCITT_BLACKIS1, encodedImage, null); + return qrcodeImage; + } + } +} \ No newline at end of file diff --git a/src/iTextSharp.LGPLv2.Core.FunctionalTests/QRCode.Apache.License/qrcode/BitArray.cs b/src/iTextSharp.LGPLv2.Core.FunctionalTests/QRCode.Apache.License/qrcode/BitArray.cs new file mode 100644 index 0000000..7a881ca --- /dev/null +++ b/src/iTextSharp.LGPLv2.Core.FunctionalTests/QRCode.Apache.License/qrcode/BitArray.cs @@ -0,0 +1,177 @@ +using System; +using System.Text; +/* + * Copyright 2007 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +namespace iTextSharp.text.pdf.qrcode { + + /** + *

A simple, fast array of bits, represented compactly by an array of ints internally.

+ * + * @author Sean Owen + */ + public sealed class BitArray { + + // TODO: I have changed these members to be public so ProGuard can inline Get() and Set(). Ideally + // they'd be private and we'd use the -allowaccessmodification flag, but Dalvik rejects the + // resulting binary at runtime on Android. If we find a solution to this, these should be changed + // back to private. + public int[] bits; + public int size; + + public BitArray(int size) { + if (size < 1) { + throw new ArgumentException("size must be at least 1"); + } + this.size = size; + this.bits = MakeArray(size); + } + + public int GetSize() { + return size; + } + + /** + * @param i bit to get + * @return true iff bit i is set + */ + public bool Get(int i) { + return (bits[i >> 5] & (1 << (i & 0x1F))) != 0; + } + + /** + * Sets bit i. + * + * @param i bit to set + */ + public void Set(int i) { + bits[i >> 5] |= 1 << (i & 0x1F); + } + + /** + * Flips bit i. + * + * @param i bit to set + */ + public void Flip(int i) { + bits[i >> 5] ^= 1 << (i & 0x1F); + } + + /** + * Sets a block of 32 bits, starting at bit i. + * + * @param i first bit to set + * @param newBits the new value of the next 32 bits. Note again that the least-significant bit + * corresponds to bit i, the next-least-significant to i+1, and so on. + */ + public void SetBulk(int i, int newBits) { + bits[i >> 5] = newBits; + } + + /** + * Clears all bits (sets to false). + */ + public void Clear() { + int max = bits.Length; + for (int i = 0; i < max; i++) { + bits[i] = 0; + } + } + + /** + * Efficient method to check if a range of bits is set, or not set. + * + * @param start start of range, inclusive. + * @param end end of range, exclusive + * @param value if true, checks that bits in range are set, otherwise checks that they are not set + * @return true iff all bits are set or not set in range, according to value argument + * @throws IllegalArgumentException if end is less than or equal to start + */ + public bool IsRange(int start, int end, bool value) { + if (end < start) { + throw new ArgumentException(); + } + if (end == start) { + return true; // empty range matches + } + end--; // will be easier to treat this as the last actually set bit -- inclusive + int firstInt = start >> 5; + int lastInt = end >> 5; + for (int i = firstInt; i <= lastInt; i++) { + int firstBit = i > firstInt ? 0 : start & 0x1F; + int lastBit = i < lastInt ? 31 : end & 0x1F; + int mask; + if (firstBit == 0 && lastBit == 31) { + mask = -1; + } + else { + mask = 0; + for (int j = firstBit; j <= lastBit; j++) { + mask |= 1 << j; + } + } + + // Return false if we're looking for 1s and the masked bits[i] isn't all 1s (that is, + // equals the mask, or we're looking for 0s and the masked portion is not all 0s + if ((bits[i] & mask) != (value ? mask : 0)) { + return false; + } + } + return true; + } + + /** + * @return underlying array of ints. The first element holds the first 32 bits, and the least + * significant bit is bit 0. + */ + public int[] GetBitArray() { + return bits; + } + + /** + * Reverses all bits in the array. + */ + public void Reverse() { + int[] newBits = new int[bits.Length]; + int size = this.size; + for (int i = 0; i < size; i++) { + if (Get(size - i - 1)) { + newBits[i >> 5] |= 1 << (i & 0x1F); + } + } + bits = newBits; + } + + private static int[] MakeArray(int size) { + int arraySize = size >> 5; + if ((size & 0x1F) != 0) { + arraySize++; + } + return new int[arraySize]; + } + + public override String ToString() { + StringBuilder result = new StringBuilder(size); + for (int i = 0; i < size; i++) { + if ((i & 0x07) == 0) { + result.Append(' '); + } + result.Append(Get(i) ? 'X' : '.'); + } + return result.ToString(); + } + } +} diff --git a/src/iTextSharp.LGPLv2.Core.FunctionalTests/QRCode.Apache.License/qrcode/BitMatrix.cs b/src/iTextSharp.LGPLv2.Core.FunctionalTests/QRCode.Apache.License/qrcode/BitMatrix.cs new file mode 100644 index 0000000..957702e --- /dev/null +++ b/src/iTextSharp.LGPLv2.Core.FunctionalTests/QRCode.Apache.License/qrcode/BitMatrix.cs @@ -0,0 +1,192 @@ +using System; +using System.Text; +/* + * Copyright 2007 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +namespace iTextSharp.text.pdf.qrcode { + + /** + *

Represents a 2D matrix of bits. In function arguments below, and throughout the common + * module, x is the column position, and y is the row position. The ordering is always x, y. + * The origin is at the top-left.

+ * + *

Internally the bits are represented in a 1-D array of 32-bit ints. However, each row begins + * with a new int. This is done intentionally so that we can copy out a row into a BitArray very + * efficiently.

+ * + *

The ordering of bits is row-major. Within each int, the least significant bits are used first, + * meaning they represent lower x values. This is compatible with BitArray's implementation.

+ * + * @author Sean Owen + * @author dswitkin@google.com (Daniel Switkin) + */ + public sealed class BitMatrix { + + // TODO: Just like BitArray, these need to be public so ProGuard can inline them. + public int width; + public int height; + public int rowSize; + public int[] bits; + + // A helper to construct a square matrix. + public BitMatrix(int dimension) : this(dimension, dimension) { + } + + public BitMatrix(int width, int height) { + if (width < 1 || height < 1) { + throw new ArgumentException("Both dimensions must be greater than 0"); + } + this.width = width; + this.height = height; + int rowSize = width >> 5; + if ((width & 0x1f) != 0) { + rowSize++; + } + this.rowSize = rowSize; + bits = new int[rowSize * height]; + } + + /** + *

Gets the requested bit, where true means black.

+ * + * @param x The horizontal component (i.e. which column) + * @param y The vertical component (i.e. which row) + * @return value of given bit in matrix + */ + public bool Get(int x, int y) { + int offset = y * rowSize + (x >> 5); + return ((bits[offset] >> (x & 0x1f)) & 1) != 0; + } + + /** + *

Sets the given bit to true.

+ * + * @param x The horizontal component (i.e. which column) + * @param y The vertical component (i.e. which row) + */ + public void Set(int x, int y) { + int offset = y * rowSize + (x >> 5); + bits[offset] |= 1 << (x & 0x1f); + } + + /** + *

Flips the given bit.

+ * + * @param x The horizontal component (i.e. which column) + * @param y The vertical component (i.e. which row) + */ + public void Flip(int x, int y) { + int offset = y * rowSize + (x >> 5); + bits[offset] ^= 1 << (x & 0x1f); + } + + /** + * Clears all bits (sets to false). + */ + public void Clear() { + int max = bits.Length; + for (int i = 0; i < max; i++) { + bits[i] = 0; + } + } + + /** + *

Sets a square region of the bit matrix to true.

+ * + * @param left The horizontal position to begin at (inclusive) + * @param top The vertical position to begin at (inclusive) + * @param width The width of the region + * @param height The height of the region + */ + public void SetRegion(int left, int top, int width, int height) { + if (top < 0 || left < 0) { + throw new ArgumentException("Left and top must be nonnegative"); + } + if (height < 1 || width < 1) { + throw new ArgumentException("Height and width must be at least 1"); + } + int right = left + width; + int bottom = top + height; + if (bottom > this.height || right > this.width) { + throw new ArgumentException("The region must fit inside the matrix"); + } + for (int y = top; y < bottom; y++) { + int offset = y * rowSize; + for (int x = left; x < right; x++) { + bits[offset + (x >> 5)] |= 1 << (x & 0x1f); + } + } + } + + /** + * A fast method to retrieve one row of data from the matrix as a BitArray. + * + * @param y The row to retrieve + * @param row An optional caller-allocated BitArray, will be allocated if null or too small + * @return The resulting BitArray - this reference should always be used even when passing + * your own row + */ + public BitArray GetRow(int y, BitArray row) { + if (row == null || row.GetSize() < width) { + row = new BitArray(width); + } + int offset = y * rowSize; + for (int x = 0; x < rowSize; x++) { + row.SetBulk(x << 5, bits[offset + x]); + } + return row; + } + + /** + * @return The width of the matrix + */ + public int GetWidth() { + return width; + } + + /** + * @return The height of the matrix + */ + public int GetHeight() { + return height; + } + + /** + * This method is for compatibility with older code. It's only logical to call if the matrix + * is square, so I'm throwing if that's not the case. + * + * @return row/column dimension of this matrix + */ + public int GetDimension() { + if (width != height) { + throw new InvalidOperationException("Can't call GetDimension() on a non-square matrix"); + } + return width; + } + + public override String ToString() { + StringBuilder result = new StringBuilder(height * (width + 1)); + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + result.Append(Get(x, y) ? "X " : " "); + } + result.Append('\n'); + } + return result.ToString(); + } + + } +} diff --git a/src/iTextSharp.LGPLv2.Core.FunctionalTests/QRCode.Apache.License/qrcode/BitVector.cs b/src/iTextSharp.LGPLv2.Core.FunctionalTests/QRCode.Apache.License/qrcode/BitVector.cs new file mode 100644 index 0000000..aba5ab1 --- /dev/null +++ b/src/iTextSharp.LGPLv2.Core.FunctionalTests/QRCode.Apache.License/qrcode/BitVector.cs @@ -0,0 +1,160 @@ +using System; +using System.Text; +/* + * Copyright 2008 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +namespace iTextSharp.text.pdf.qrcode { + + /** + * JAVAPORT: This should be combined with BitArray in the future, although that class is not yet + * dynamically resizeable. This implementation is reasonable but there is a lot of function calling + * in loops I'd like to get rid of. + * + * @author satorux@google.com (Satoru Takabayashi) - creator + * @author dswitkin@google.com (Daniel Switkin) - ported from C++ + */ + public sealed class BitVector { + + private int sizeInBits; + private byte[] array; + + // For efficiency, start out with some room to work. + private const int DEFAULT_SIZE_IN_BYTES = 32; + + public BitVector() { + sizeInBits = 0; + array = new byte[DEFAULT_SIZE_IN_BYTES]; + } + + // Return the bit value at "index". + public int At(int index) { + if (index < 0 || index >= sizeInBits) { + throw new IndexOutOfRangeException("Bad index: " + index); + } + int value = array[index >> 3] & 0xff; + return (value >> (7 - (index & 0x7))) & 1; + } + + // Return the number of bits in the bit vector. + public int Size() { + return sizeInBits; + } + + // Return the number of bytes in the bit vector. + public int SizeInBytes() { + return (sizeInBits + 7) >> 3; + } + + // Append one bit to the bit vector. + public void AppendBit(int bit) { + if (!(bit == 0 || bit == 1)) { + throw new ArgumentException("Bad bit"); + } + int numBitsInLastByte = sizeInBits & 0x7; + // We'll expand array if we don't have bits in the last byte. + if (numBitsInLastByte == 0) { + AppendByte(0); + sizeInBits -= 8; + } + // Modify the last byte. + array[sizeInBits >> 3] |= (byte)(bit << (7 - numBitsInLastByte)); + ++sizeInBits; + } + + // Append "numBits" bits in "value" to the bit vector. + // REQUIRES: 0<= numBits <= 32. + // + // Examples: + // - AppendBits(0x00, 1) adds 0. + // - AppendBits(0x00, 4) adds 0000. + // - AppendBits(0xff, 8) adds 11111111. + public void AppendBits(int value, int numBits) { + if (numBits < 0 || numBits > 32) { + throw new ArgumentException("Num bits must be between 0 and 32"); + } + int numBitsLeft = numBits; + while (numBitsLeft > 0) { + // Optimization for byte-oriented appending. + if ((sizeInBits & 0x7) == 0 && numBitsLeft >= 8) { + int newByte = (value >> (numBitsLeft - 8)) & 0xff; + AppendByte(newByte); + numBitsLeft -= 8; + } + else { + int bit = (value >> (numBitsLeft - 1)) & 1; + AppendBit(bit); + --numBitsLeft; + } + } + } + + // Append "bits". + public void AppendBitVector(BitVector bits) { + int size = bits.Size(); + for (int i = 0; i < size; ++i) { + AppendBit(bits.At(i)); + } + } + + // Modify the bit vector by XOR'ing with "other" + public void Xor(BitVector other) { + if (sizeInBits != other.Size()) { + throw new ArgumentException("BitVector sizes don't match"); + } + int sizeInBytes = (sizeInBits + 7) >> 3; + for (int i = 0; i < sizeInBytes; ++i) { + // The last byte could be incomplete (i.e. not have 8 bits in + // it) but there is no problem since 0 XOR 0 == 0. + array[i] ^= other.array[i]; + } + } + + // Return String like "01110111" for debugging. + public override String ToString() { + StringBuilder result = new StringBuilder(sizeInBits); + for (int i = 0; i < sizeInBits; ++i) { + if (At(i) == 0) { + result.Append('0'); + } + else if (At(i) == 1) { + result.Append('1'); + } + else { + throw new ArgumentException("Byte isn't 0 or 1"); + } + } + return result.ToString(); + } + + // Callers should not assume that array.length is the exact number of bytes needed to hold + // sizeInBits - it will typically be larger for efficiency. + public byte[] GetArray() { + return array; + } + + // Add a new byte to the end, possibly reallocating and doubling the size of the array if we've + // run out of room. + private void AppendByte(int value) { + if ((sizeInBits >> 3) == array.Length) { + byte[] newArray = new byte[(array.Length << 1)]; + System.Array.Copy(array, 0, newArray, 0, array.Length); + array = newArray; + } + array[sizeInBits >> 3] = (byte)value; + sizeInBits += 8; + } + } +} diff --git a/src/iTextSharp.LGPLv2.Core.FunctionalTests/QRCode.Apache.License/qrcode/BlockPair.cs b/src/iTextSharp.LGPLv2.Core.FunctionalTests/QRCode.Apache.License/qrcode/BlockPair.cs new file mode 100644 index 0000000..198b8da --- /dev/null +++ b/src/iTextSharp.LGPLv2.Core.FunctionalTests/QRCode.Apache.License/qrcode/BlockPair.cs @@ -0,0 +1,39 @@ +using System; +/* + * Copyright 2008 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +namespace iTextSharp.text.pdf.qrcode { + + public sealed class BlockPair { + + private ByteArray dataBytes; + private ByteArray errorCorrectionBytes; + + internal BlockPair(ByteArray data, ByteArray errorCorrection) { + dataBytes = data; + errorCorrectionBytes = errorCorrection; + } + + public ByteArray GetDataBytes() { + return dataBytes; + } + + public ByteArray GetErrorCorrectionBytes() { + return errorCorrectionBytes; + } + + } +} diff --git a/src/iTextSharp.LGPLv2.Core.FunctionalTests/QRCode.Apache.License/qrcode/ByteArray.cs b/src/iTextSharp.LGPLv2.Core.FunctionalTests/QRCode.Apache.License/qrcode/ByteArray.cs new file mode 100644 index 0000000..e9957f2 --- /dev/null +++ b/src/iTextSharp.LGPLv2.Core.FunctionalTests/QRCode.Apache.License/qrcode/ByteArray.cs @@ -0,0 +1,97 @@ +using System; +/* + * Copyright 2008 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +namespace iTextSharp.text.pdf.qrcode { + + /** + * This class implements an array of unsigned bytes. + * + * @author dswitkin@google.com (Daniel Switkin) + */ + public sealed class ByteArray { + + private const int INITIAL_SIZE = 32; + + private byte[] bytes; + private int size; + + public ByteArray() { + bytes = null; + size = 0; + } + + public ByteArray(int size) { + bytes = new byte[size]; + this.size = size; + } + + public ByteArray(byte[] byteArray) { + bytes = byteArray; + size = bytes.Length; + } + + /** + * Access an unsigned byte at location index. + * @param index The index in the array to access. + * @return The unsigned value of the byte as an int. + */ + public int At(int index) { + return bytes[index] & 0xff; + } + + public void Set(int index, int value) { + bytes[index] = (byte)value; + } + + public int Size() { + return size; + } + + public bool IsEmpty() { + return size == 0; + } + + public void AppendByte(int value) { + if (size == 0 || size >= bytes.Length) { + int newSize = Math.Max(INITIAL_SIZE, size << 1); + Reserve(newSize); + } + bytes[size] = (byte)value; + size++; + } + + public void Reserve(int capacity) { + if (bytes == null || bytes.Length < capacity) { + byte[] newArray = new byte[capacity]; + if (bytes != null) { + System.Array.Copy(bytes, 0, newArray, 0, bytes.Length); + } + bytes = newArray; + } + } + + // Copy count bytes from array source starting at offset. + public void Set(byte[] source, int offset, int count) { + bytes = new byte[count]; + size = count; + for (int x = 0; x < count; x++) { + bytes[x] = source[offset + x]; + } + } + + } +} diff --git a/src/iTextSharp.LGPLv2.Core.FunctionalTests/QRCode.Apache.License/qrcode/ByteMatrix.cs b/src/iTextSharp.LGPLv2.Core.FunctionalTests/QRCode.Apache.License/qrcode/ByteMatrix.cs new file mode 100644 index 0000000..0d227da --- /dev/null +++ b/src/iTextSharp.LGPLv2.Core.FunctionalTests/QRCode.Apache.License/qrcode/ByteMatrix.cs @@ -0,0 +1,98 @@ +using System; +using System.Text; +/* + * Copyright 2008 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +namespace iTextSharp.text.pdf.qrcode { + + /** + * A class which wraps a 2D array of bytes. The default usage is signed. If you want to use it as a + * unsigned container, it's up to you to do byteValue & 0xff at each location. + * + * JAVAPORT: The original code was a 2D array of ints, but since it only ever gets assigned + * -1, 0, and 1, I'm going to use less memory and go with bytes. + * + * @author dswitkin@google.com (Daniel Switkin) + */ + public sealed class ByteMatrix { + + private sbyte[][] bytes; + private int width; + private int height; + + public ByteMatrix(int width, int height) { + bytes = new sbyte[height][]; + for (int k = 0; k < height; ++k) { + bytes[k] = new sbyte[width]; + } + this.width = width; + this.height = height; + } + + public int GetHeight() { + return height; + } + + public int GetWidth() { + return width; + } + + public sbyte Get(int x, int y) { + return bytes[y][x]; + } + + public sbyte[][] GetArray() { + return bytes; + } + + public void Set(int x, int y, sbyte value) { + bytes[y][x] = value; + } + + public void Set(int x, int y, int value) { + bytes[y][x] = (sbyte)value; + } + + public void Clear(sbyte value) { + for (int y = 0; y < height; ++y) { + for (int x = 0; x < width; ++x) { + bytes[y][x] = value; + } + } + } + + public override String ToString() { + StringBuilder result = new StringBuilder(2 * width * height + 2); + for (int y = 0; y < height; ++y) { + for (int x = 0; x < width; ++x) { + switch (bytes[y][x]) { + case 0: + result.Append(" 0"); + break; + case 1: + result.Append(" 1"); + break; + default: + result.Append(" "); + break; + } + } + result.Append('\n'); + } + return result.ToString(); + } + } +} diff --git a/src/iTextSharp.LGPLv2.Core.FunctionalTests/QRCode.Apache.License/qrcode/CharacterSetECI.cs b/src/iTextSharp.LGPLv2.Core.FunctionalTests/QRCode.Apache.License/qrcode/CharacterSetECI.cs new file mode 100644 index 0000000..bc55bc9 --- /dev/null +++ b/src/iTextSharp.LGPLv2.Core.FunctionalTests/QRCode.Apache.License/qrcode/CharacterSetECI.cs @@ -0,0 +1,98 @@ +using System; +using System.Collections.Generic; +/* + * Copyright 2008 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +namespace iTextSharp.text.pdf.qrcode { + + /** + * Encapsulates a Character Set ECI, according to "Extended Channel Interpretations" 5.3.1.1 + * of ISO 18004. + * + * @author Sean Owen + */ + public class CharacterSetECI { + + private static Dictionary NAME_TO_ECI; + + private static void Initialize() { + Dictionary n = new Dictionary(); + // TODO figure out if these values are even right! + AddCharacterSet(0, "Cp437", n); + AddCharacterSet(1, new String[] { "ISO8859_1", "ISO-8859-1" }, n); + AddCharacterSet(2, "Cp437", n); + AddCharacterSet(3, new String[] { "ISO8859_1", "ISO-8859-1" }, n); + AddCharacterSet(4, new String[] { "ISO8859_2", "ISO-8859-2" }, n); + AddCharacterSet(5, new String[] { "ISO8859_3", "ISO-8859-3" }, n); + AddCharacterSet(6, new String[] { "ISO8859_4", "ISO-8859-4" }, n); + AddCharacterSet(7, new String[] { "ISO8859_5", "ISO-8859-5" }, n); + AddCharacterSet(8, new String[] { "ISO8859_6", "ISO-8859-6" }, n); + AddCharacterSet(9, new String[] { "ISO8859_7", "ISO-8859-7" }, n); + AddCharacterSet(10, new String[] { "ISO8859_8", "ISO-8859-8" }, n); + AddCharacterSet(11, new String[] { "ISO8859_9", "ISO-8859-9" }, n); + AddCharacterSet(12, new String[] { "ISO8859_10", "ISO-8859-10" }, n); + AddCharacterSet(13, new String[] { "ISO8859_11", "ISO-8859-11" }, n); + AddCharacterSet(15, new String[] { "ISO8859_13", "ISO-8859-13" }, n); + AddCharacterSet(16, new String[] { "ISO8859_14", "ISO-8859-14" }, n); + AddCharacterSet(17, new String[] { "ISO8859_15", "ISO-8859-15" }, n); + AddCharacterSet(18, new String[] { "ISO8859_16", "ISO-8859-16" }, n); + AddCharacterSet(20, new String[] { "SJIS", "Shift_JIS" }, n); + NAME_TO_ECI = n; + } + + private String encodingName; + private int value; + + private CharacterSetECI(int value, String encodingName) { + this.value = value; + this.encodingName = encodingName; + } + + virtual public String GetEncodingName() { + return encodingName; + } + + virtual public int GetValue() { + return value; + } + + private static void AddCharacterSet(int value, String encodingName, Dictionary n) { + CharacterSetECI eci = new CharacterSetECI(value, encodingName); + n[encodingName] = eci; + } + + private static void AddCharacterSet(int value, String[] encodingNames, Dictionary n) { + CharacterSetECI eci = new CharacterSetECI(value, encodingNames[0]); + for (int i = 0; i < encodingNames.Length; i++) { + n[encodingNames[i]] = eci; + } + } + + /** + * @param name character set ECI encoding name + * @return {@link CharacterSetECI} representing ECI for character encoding, or null if it is legal + * but unsupported + */ + public static CharacterSetECI GetCharacterSetECIByName(String name) { + if (NAME_TO_ECI == null) { + Initialize(); + } + CharacterSetECI c; + NAME_TO_ECI.TryGetValue(name, out c); + return c; + } + } +} diff --git a/src/iTextSharp.LGPLv2.Core.FunctionalTests/QRCode.Apache.License/qrcode/EncodeHintType.cs b/src/iTextSharp.LGPLv2.Core.FunctionalTests/QRCode.Apache.License/qrcode/EncodeHintType.cs new file mode 100644 index 0000000..25d5cbf --- /dev/null +++ b/src/iTextSharp.LGPLv2.Core.FunctionalTests/QRCode.Apache.License/qrcode/EncodeHintType.cs @@ -0,0 +1,40 @@ +using System; +/* + * Copyright 2008 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +namespace iTextSharp.text.pdf.qrcode { + + /** + * These are a set of hints that you may pass to Writers to specify their behavior. + * + * @author dswitkin@google.com (Daniel Switkin) + */ + public sealed class EncodeHintType { + + /** + * Specifies what degree of error correction to use, for example in QR Codes (type Integer). + */ + public static readonly EncodeHintType ERROR_CORRECTION = new EncodeHintType(); + + /** + * Specifies what character encoding to use where applicable (type String) + */ + public static readonly EncodeHintType CHARACTER_SET = new EncodeHintType(); + + private EncodeHintType() { + } + } +} diff --git a/src/iTextSharp.LGPLv2.Core.FunctionalTests/QRCode.Apache.License/qrcode/Encoder.cs b/src/iTextSharp.LGPLv2.Core.FunctionalTests/QRCode.Apache.License/qrcode/Encoder.cs new file mode 100644 index 0000000..eaac786 --- /dev/null +++ b/src/iTextSharp.LGPLv2.Core.FunctionalTests/QRCode.Apache.License/qrcode/Encoder.cs @@ -0,0 +1,570 @@ +using System; +using System.Collections.Generic; +using System.Text; +/* + * Copyright 2008 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +namespace iTextSharp.text.pdf.qrcode { + + /** + * @author satorux@google.com (Satoru Takabayashi) - creator + * @author dswitkin@google.com (Daniel Switkin) - ported from C++ + */ + public sealed class Encoder { + + // The original table is defined in the table 5 of JISX0510:2004 (p.19). + private static readonly int[] ALPHANUMERIC_TABLE = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0x00-0x0f + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0x10-0x1f + 36, -1, -1, -1, 37, 38, -1, -1, -1, -1, 39, 40, -1, 41, 42, 43, // 0x20-0x2f + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 44, -1, -1, -1, -1, -1, // 0x30-0x3f + -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, // 0x40-0x4f + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1 // 0x50-0x5f + }; + + private const String DEFAULT_BYTE_MODE_ENCODING = "ISO-8859-1"; + + private Encoder() { + } + + // The mask penalty calculation is complicated. See Table 21 of JISX0510:2004 (p.45) for details. + // Basically it applies four rules and summate all penalties. + private static int CalculateMaskPenalty(ByteMatrix matrix) { + int penalty = 0; + penalty += MaskUtil.ApplyMaskPenaltyRule1(matrix); + penalty += MaskUtil.ApplyMaskPenaltyRule2(matrix); + penalty += MaskUtil.ApplyMaskPenaltyRule3(matrix); + penalty += MaskUtil.ApplyMaskPenaltyRule4(matrix); + return penalty; + } + + /** + * Encode "bytes" with the error correction level "ecLevel". The encoding mode will be chosen + * internally by ChooseMode(). On success, store the result in "qrCode". + * + * We recommend you to use QRCode.EC_LEVEL_L (the lowest level) for + * "getECLevel" since our primary use is to show QR code on desktop screens. We don't need very + * strong error correction for this purpose. + * + * Note that there is no way to encode bytes in MODE_KANJI. We might want to add EncodeWithMode() + * with which clients can specify the encoding mode. For now, we don't need the functionality. + */ + public static void Encode(String content, ErrorCorrectionLevel ecLevel, QRCode qrCode) { + Encode(content, ecLevel, null, qrCode); + } + + public static void Encode(String content, ErrorCorrectionLevel ecLevel, IDictionary hints, + QRCode qrCode) { + + String encoding = null; + if (hints != null && hints.ContainsKey(EncodeHintType.CHARACTER_SET)) + encoding = (string)hints[EncodeHintType.CHARACTER_SET]; + if (encoding == null) { + encoding = DEFAULT_BYTE_MODE_ENCODING; + } + + // Step 1: Choose the mode (encoding). + Mode mode = ChooseMode(content, encoding); + + // Step 2: Append "bytes" into "dataBits" in appropriate encoding. + BitVector dataBits = new BitVector(); + AppendBytes(content, mode, dataBits, encoding); + // Step 3: Initialize QR code that can contain "dataBits". + int numInputBytes = dataBits.SizeInBytes(); + InitQRCode(numInputBytes, ecLevel, mode, qrCode); + + // Step 4: Build another bit vector that contains header and data. + BitVector headerAndDataBits = new BitVector(); + + // Step 4.5: Append ECI message if applicable + if (mode == Mode.BYTE && !DEFAULT_BYTE_MODE_ENCODING.Equals(encoding)) { + CharacterSetECI eci = CharacterSetECI.GetCharacterSetECIByName(encoding); + if (eci != null) { + AppendECI(eci, headerAndDataBits); + } + } + + AppendModeInfo(mode, headerAndDataBits); + + int numLetters = mode.Equals(Mode.BYTE) ? dataBits.SizeInBytes() : content.Length; + AppendLengthInfo(numLetters, qrCode.GetVersion(), mode, headerAndDataBits); + headerAndDataBits.AppendBitVector(dataBits); + + // Step 5: Terminate the bits properly. + TerminateBits(qrCode.GetNumDataBytes(), headerAndDataBits); + + // Step 6: Interleave data bits with error correction code. + BitVector finalBits = new BitVector(); + InterleaveWithECBytes(headerAndDataBits, qrCode.GetNumTotalBytes(), qrCode.GetNumDataBytes(), + qrCode.GetNumRSBlocks(), finalBits); + + // Step 7: Choose the mask pattern and set to "qrCode". + ByteMatrix matrix = new ByteMatrix(qrCode.GetMatrixWidth(), qrCode.GetMatrixWidth()); + qrCode.SetMaskPattern(ChooseMaskPattern(finalBits, qrCode.GetECLevel(), qrCode.GetVersion(), + matrix)); + + // Step 8. Build the matrix and set it to "qrCode". + MatrixUtil.BuildMatrix(finalBits, qrCode.GetECLevel(), qrCode.GetVersion(), + qrCode.GetMaskPattern(), matrix); + qrCode.SetMatrix(matrix); + // Step 9. Make sure we have a valid QR Code. + if (!qrCode.IsValid()) { + throw new WriterException("Invalid QR code: " + qrCode.ToString()); + } + } + + /** + * @return the code point of the table used in alphanumeric mode or + * -1 if there is no corresponding code in the table. + */ + static int GetAlphanumericCode(int code) { + if (code < ALPHANUMERIC_TABLE.Length) { + return ALPHANUMERIC_TABLE[code]; + } + return -1; + } + + public static Mode ChooseMode(String content) { + return ChooseMode(content, null); + } + + /** + * Choose the best mode by examining the content. Note that 'encoding' is used as a hint; + * if it is Shift_JIS, and the input is only double-byte Kanji, then we return {@link Mode#KANJI}. + */ + public static Mode ChooseMode(String content, String encoding) { + if ("Shift_JIS".Equals(encoding)) { + // Choose Kanji mode if all input are double-byte characters + return IsOnlyDoubleByteKanji(content) ? Mode.KANJI : Mode.BYTE; + } + bool hasNumeric = false; + bool hasAlphanumeric = false; + for (int i = 0; i < content.Length; ++i) { + char c = content[i]; + if (c >= '0' && c <= '9') { + hasNumeric = true; + } + else if (GetAlphanumericCode(c) != -1) { + hasAlphanumeric = true; + } + else { + return Mode.BYTE; + } + } + if (hasAlphanumeric) { + return Mode.ALPHANUMERIC; + } + else if (hasNumeric) { + return Mode.NUMERIC; + } + return Mode.BYTE; + } + + private static bool IsOnlyDoubleByteKanji(String content) { + byte[] bytes; + try { + bytes = Encoding.GetEncoding("Shift_JIS").GetBytes(content); + } + catch { + return false; + } + int length = bytes.Length; + if (length % 2 != 0) { + return false; + } + for (int i = 0; i < length; i += 2) { + int byte1 = bytes[i] & 0xFF; + if ((byte1 < 0x81 || byte1 > 0x9F) && (byte1 < 0xE0 || byte1 > 0xEB)) { + return false; + } + } + return true; + } + + private static int ChooseMaskPattern(BitVector bits, ErrorCorrectionLevel ecLevel, int version, + ByteMatrix matrix) { + + int minPenalty = int.MaxValue; // Lower penalty is better. + int bestMaskPattern = -1; + // We try all mask patterns to choose the best one. + for (int maskPattern = 0; maskPattern < QRCode.NUM_MASK_PATTERNS; maskPattern++) { + MatrixUtil.BuildMatrix(bits, ecLevel, version, maskPattern, matrix); + int penalty = CalculateMaskPenalty(matrix); + if (penalty < minPenalty) { + minPenalty = penalty; + bestMaskPattern = maskPattern; + } + } + return bestMaskPattern; + } + + /** + * Initialize "qrCode" according to "numInputBytes", "ecLevel", and "mode". On success, + * modify "qrCode". + */ + private static void InitQRCode(int numInputBytes, ErrorCorrectionLevel ecLevel, Mode mode, + QRCode qrCode) { + qrCode.SetECLevel(ecLevel); + qrCode.SetMode(mode); + + // In the following comments, we use numbers of Version 7-H. + for (int versionNum = 1; versionNum <= 40; versionNum++) { + Version version = Version.GetVersionForNumber(versionNum); + // numBytes = 196 + int numBytes = version.GetTotalCodewords(); + // getNumECBytes = 130 + Version.ECBlocks ecBlocks = version.GetECBlocksForLevel(ecLevel); + int numEcBytes = ecBlocks.GetTotalECCodewords(); + // getNumRSBlocks = 5 + int numRSBlocks = ecBlocks.GetNumBlocks(); + // getNumDataBytes = 196 - 130 = 66 + int numDataBytes = numBytes - numEcBytes; + // We want to choose the smallest version which can contain data of "numInputBytes" + some + // extra bits for the header (mode info and length info). The header can be three bytes + // (precisely 4 + 16 bits) at most. Hence we do +3 here. + if (numDataBytes >= numInputBytes + 3) { + // Yay, we found the proper rs block info! + qrCode.SetVersion(versionNum); + qrCode.SetNumTotalBytes(numBytes); + qrCode.SetNumDataBytes(numDataBytes); + qrCode.SetNumRSBlocks(numRSBlocks); + // getNumECBytes = 196 - 66 = 130 + qrCode.SetNumECBytes(numEcBytes); + // matrix width = 21 + 6 * 4 = 45 + qrCode.SetMatrixWidth(version.GetDimensionForVersion()); + return; + } + } + throw new WriterException("Cannot find proper rs block info (input data too big?)"); + } + + /** + * Terminate bits as described in 8.4.8 and 8.4.9 of JISX0510:2004 (p.24). + */ + static void TerminateBits(int numDataBytes, BitVector bits) { + int capacity = numDataBytes << 3; + if (bits.Size() > capacity) { + throw new WriterException("data bits cannot fit in the QR Code" + bits.Size() + " > " + + capacity); + } + // Append termination bits. See 8.4.8 of JISX0510:2004 (p.24) for details. + // TODO: srowen says we can remove this for loop, since the 4 terminator bits are optional if + // the last byte has less than 4 bits left. So it amounts to padding the last byte with zeroes + // either way. + for (int i = 0; i < 4 && bits.Size() < capacity; ++i) { + bits.AppendBit(0); + } + int numBitsInLastByte = bits.Size() % 8; + // If the last byte isn't 8-bit aligned, we'll add padding bits. + if (numBitsInLastByte > 0) { + int numPaddingBits = 8 - numBitsInLastByte; + for (int i = 0; i < numPaddingBits; ++i) { + bits.AppendBit(0); + } + } + // Should be 8-bit aligned here. + if (bits.Size() % 8 != 0) { + throw new WriterException("Number of bits is not a multiple of 8"); + } + // If we have more space, we'll fill the space with padding patterns defined in 8.4.9 (p.24). + int numPaddingBytes = numDataBytes - bits.SizeInBytes(); + for (int i = 0; i < numPaddingBytes; ++i) { + if (i % 2 == 0) { + bits.AppendBits(0xec, 8); + } + else { + bits.AppendBits(0x11, 8); + } + } + if (bits.Size() != capacity) { + throw new WriterException("Bits size does not equal capacity"); + } + } + + /** + * Get number of data bytes and number of error correction bytes for block id "blockID". Store + * the result in "numDataBytesInBlock", and "numECBytesInBlock". See table 12 in 8.5.1 of + * JISX0510:2004 (p.30) + */ + static void GetNumDataBytesAndNumECBytesForBlockID(int numTotalBytes, int numDataBytes, + int numRSBlocks, int blockID, int[] numDataBytesInBlock, + int[] numECBytesInBlock) { + if (blockID >= numRSBlocks) { + throw new WriterException("Block ID too large"); + } + // numRsBlocksInGroup2 = 196 % 5 = 1 + int numRsBlocksInGroup2 = numTotalBytes % numRSBlocks; + // numRsBlocksInGroup1 = 5 - 1 = 4 + int numRsBlocksInGroup1 = numRSBlocks - numRsBlocksInGroup2; + // numTotalBytesInGroup1 = 196 / 5 = 39 + int numTotalBytesInGroup1 = numTotalBytes / numRSBlocks; + // numTotalBytesInGroup2 = 39 + 1 = 40 + int numTotalBytesInGroup2 = numTotalBytesInGroup1 + 1; + // numDataBytesInGroup1 = 66 / 5 = 13 + int numDataBytesInGroup1 = numDataBytes / numRSBlocks; + // numDataBytesInGroup2 = 13 + 1 = 14 + int numDataBytesInGroup2 = numDataBytesInGroup1 + 1; + // numEcBytesInGroup1 = 39 - 13 = 26 + int numEcBytesInGroup1 = numTotalBytesInGroup1 - numDataBytesInGroup1; + // numEcBytesInGroup2 = 40 - 14 = 26 + int numEcBytesInGroup2 = numTotalBytesInGroup2 - numDataBytesInGroup2; + // Sanity checks. + // 26 = 26 + if (numEcBytesInGroup1 != numEcBytesInGroup2) { + throw new WriterException("EC bytes mismatch"); + } + // 5 = 4 + 1. + if (numRSBlocks != numRsBlocksInGroup1 + numRsBlocksInGroup2) { + throw new WriterException("RS blocks mismatch"); + } + // 196 = (13 + 26) * 4 + (14 + 26) * 1 + if (numTotalBytes != + ((numDataBytesInGroup1 + numEcBytesInGroup1) * + numRsBlocksInGroup1) + + ((numDataBytesInGroup2 + numEcBytesInGroup2) * + numRsBlocksInGroup2)) { + throw new WriterException("Total bytes mismatch"); + } + + if (blockID < numRsBlocksInGroup1) { + numDataBytesInBlock[0] = numDataBytesInGroup1; + numECBytesInBlock[0] = numEcBytesInGroup1; + } + else { + numDataBytesInBlock[0] = numDataBytesInGroup2; + numECBytesInBlock[0] = numEcBytesInGroup2; + } + } + + /** + * Interleave "bits" with corresponding error correction bytes. On success, store the result in + * "result". The interleave rule is complicated. See 8.6 of JISX0510:2004 (p.37) for details. + */ + static void InterleaveWithECBytes(BitVector bits, int numTotalBytes, + int numDataBytes, int numRSBlocks, BitVector result) { + + // "bits" must have "getNumDataBytes" bytes of data. + if (bits.SizeInBytes() != numDataBytes) { + throw new WriterException("Number of bits and data bytes does not match"); + } + + // Step 1. Divide data bytes into blocks and generate error correction bytes for them. We'll + // store the divided data bytes blocks and error correction bytes blocks into "blocks". + int dataBytesOffset = 0; + int maxNumDataBytes = 0; + int maxNumEcBytes = 0; + + // Since, we know the number of reedsolmon blocks, we can initialize the vector with the number. + List blocks = new List(numRSBlocks); + + for (int i = 0; i < numRSBlocks; ++i) { + int[] numDataBytesInBlock = new int[1]; + int[] numEcBytesInBlock = new int[1]; + GetNumDataBytesAndNumECBytesForBlockID( + numTotalBytes, numDataBytes, numRSBlocks, i, + numDataBytesInBlock, numEcBytesInBlock); + + ByteArray dataBytes = new ByteArray(); + dataBytes.Set(bits.GetArray(), dataBytesOffset, numDataBytesInBlock[0]); + ByteArray ecBytes = GenerateECBytes(dataBytes, numEcBytesInBlock[0]); + blocks.Add(new BlockPair(dataBytes, ecBytes)); + + maxNumDataBytes = Math.Max(maxNumDataBytes, dataBytes.Size()); + maxNumEcBytes = Math.Max(maxNumEcBytes, ecBytes.Size()); + dataBytesOffset += numDataBytesInBlock[0]; + } + if (numDataBytes != dataBytesOffset) { + throw new WriterException("Data bytes does not match offset"); + } + + // First, place data blocks. + for (int i = 0; i < maxNumDataBytes; ++i) { + for (int j = 0; j < blocks.Count; ++j) { + ByteArray dataBytes = blocks[j].GetDataBytes(); + if (i < dataBytes.Size()) { + result.AppendBits(dataBytes.At(i), 8); + } + } + } + // Then, place error correction blocks. + for (int i = 0; i < maxNumEcBytes; ++i) { + for (int j = 0; j < blocks.Count; ++j) { + ByteArray ecBytes = blocks[j].GetErrorCorrectionBytes(); + if (i < ecBytes.Size()) { + result.AppendBits(ecBytes.At(i), 8); + } + } + } + if (numTotalBytes != result.SizeInBytes()) { // Should be same. + throw new WriterException("Interleaving error: " + numTotalBytes + " and " + + result.SizeInBytes() + " differ."); + } + } + + static ByteArray GenerateECBytes(ByteArray dataBytes, int numEcBytesInBlock) { + int numDataBytes = dataBytes.Size(); + int[] toEncode = new int[numDataBytes + numEcBytesInBlock]; + for (int i = 0; i < numDataBytes; i++) { + toEncode[i] = dataBytes.At(i); + } + new ReedSolomonEncoder(GF256.QR_CODE_FIELD).Encode(toEncode, numEcBytesInBlock); + + ByteArray ecBytes = new ByteArray(numEcBytesInBlock); + for (int i = 0; i < numEcBytesInBlock; i++) { + ecBytes.Set(i, toEncode[numDataBytes + i]); + } + return ecBytes; + } + + /** + * Append mode info. On success, store the result in "bits". + */ + static void AppendModeInfo(Mode mode, BitVector bits) { + bits.AppendBits(mode.GetBits(), 4); + } + + + /** + * Append length info. On success, store the result in "bits". + */ + static void AppendLengthInfo(int numLetters, int version, Mode mode, BitVector bits) { + int numBits = mode.GetCharacterCountBits(Version.GetVersionForNumber(version)); + if (numLetters > ((1 << numBits) - 1)) { + throw new WriterException(numLetters + "is bigger than" + ((1 << numBits) - 1)); + } + bits.AppendBits(numLetters, numBits); + } + + /** + * Append "bytes" in "mode" mode (encoding) into "bits". On success, store the result in "bits". + */ + static void AppendBytes(String content, Mode mode, BitVector bits, String encoding) { + if (mode.Equals(Mode.NUMERIC)) { + AppendNumericBytes(content, bits); + } + else if (mode.Equals(Mode.ALPHANUMERIC)) { + AppendAlphanumericBytes(content, bits); + } + else if (mode.Equals(Mode.BYTE)) { + Append8BitBytes(content, bits, encoding); + } + else if (mode.Equals(Mode.KANJI)) { + AppendKanjiBytes(content, bits); + } + else { + throw new WriterException("Invalid mode: " + mode); + } + } + + static void AppendNumericBytes(String content, BitVector bits) { + int length = content.Length; + int i = 0; + while (i < length) { + int num1 = content[i] - '0'; + if (i + 2 < length) { + // Encode three numeric letters in ten bits. + int num2 = content[i + 1] - '0'; + int num3 = content[i + 2] - '0'; + bits.AppendBits(num1 * 100 + num2 * 10 + num3, 10); + i += 3; + } + else if (i + 1 < length) { + // Encode two numeric letters in seven bits. + int num2 = content[i + 1] - '0'; + bits.AppendBits(num1 * 10 + num2, 7); + i += 2; + } + else { + // Encode one numeric letter in four bits. + bits.AppendBits(num1, 4); + i++; + } + } + } + + static void AppendAlphanumericBytes(String content, BitVector bits) { + int length = content.Length; + int i = 0; + while (i < length) { + int code1 = GetAlphanumericCode(content[i]); + if (code1 == -1) { + throw new WriterException(); + } + if (i + 1 < length) { + int code2 = GetAlphanumericCode(content[i + 1]); + if (code2 == -1) { + throw new WriterException(); + } + // Encode two alphanumeric letters in 11 bits. + bits.AppendBits(code1 * 45 + code2, 11); + i += 2; + } + else { + // Encode one alphanumeric letter in six bits. + bits.AppendBits(code1, 6); + i++; + } + } + } + + static void Append8BitBytes(String content, BitVector bits, String encoding) { + byte[] bytes; + try { + bytes = Encoding.GetEncoding(encoding).GetBytes(content); + } + catch (Exception uee) { + throw new WriterException(uee.Message); + } + for (int i = 0; i < bytes.Length; ++i) { + bits.AppendBits(bytes[i], 8); + } + } + + static void AppendKanjiBytes(String content, BitVector bits) { + byte[] bytes; + try { + bytes = Encoding.GetEncoding("Shift_JIS").GetBytes(content); + } + catch (Exception uee) { + throw new WriterException(uee.Message); + } + int length = bytes.Length; + for (int i = 0; i < length; i += 2) { + int byte1 = bytes[i] & 0xFF; + int byte2 = bytes[i + 1] & 0xFF; + int code = (byte1 << 8) | byte2; + int subtracted = -1; + if (code >= 0x8140 && code <= 0x9ffc) { + subtracted = code - 0x8140; + } + else if (code >= 0xe040 && code <= 0xebbf) { + subtracted = code - 0xc140; + } + if (subtracted == -1) { + throw new WriterException("Invalid byte sequence"); + } + int encoded = ((subtracted >> 8) * 0xc0) + (subtracted & 0xff); + bits.AppendBits(encoded, 13); + } + } + + private static void AppendECI(CharacterSetECI eci, BitVector bits) { + bits.AppendBits(Mode.ECI.GetBits(), 4); + // This is correct for values up to 127, which is all we need now. + bits.AppendBits(eci.GetValue(), 8); + } + } +} diff --git a/src/iTextSharp.LGPLv2.Core.FunctionalTests/QRCode.Apache.License/qrcode/ErrorCorrectionLevel.cs b/src/iTextSharp.LGPLv2.Core.FunctionalTests/QRCode.Apache.License/qrcode/ErrorCorrectionLevel.cs new file mode 100644 index 0000000..00622fc --- /dev/null +++ b/src/iTextSharp.LGPLv2.Core.FunctionalTests/QRCode.Apache.License/qrcode/ErrorCorrectionLevel.cs @@ -0,0 +1,84 @@ +using System; +/* + * Copyright 2007 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +namespace iTextSharp.text.pdf.qrcode { + + /** + *

See ISO 18004:2006, 6.5.1. This enum encapsulates the four error correction levels + * defined by the QR code standard.

+ * + * @author Sean Owen + */ + public sealed class ErrorCorrectionLevel { + + /** + * L = ~7% correction + */ + public static readonly ErrorCorrectionLevel L = new ErrorCorrectionLevel(0, 0x01, "L"); + /** + * M = ~15% correction + */ + public static readonly ErrorCorrectionLevel M = new ErrorCorrectionLevel(1, 0x00, "M"); + /** + * Q = ~25% correction + */ + public static readonly ErrorCorrectionLevel Q = new ErrorCorrectionLevel(2, 0x03, "Q"); + /** + * H = ~30% correction + */ + public static readonly ErrorCorrectionLevel H = new ErrorCorrectionLevel(3, 0x02, "H"); + + private static readonly ErrorCorrectionLevel[] FOR_BITS = { M, L, H, Q }; + + private int ordinal; + private int bits; + private String name; + + private ErrorCorrectionLevel(int ordinal, int bits, String name) { + this.ordinal = ordinal; + this.bits = bits; + this.name = name; + } + + public int Ordinal() { + return ordinal; + } + + public int GetBits() { + return bits; + } + + public String GetName() { + return name; + } + + public override String ToString() { + return name; + } + + /** + * @param bits int containing the two bits encoding a QR Code's error correction level + * @return {@link ErrorCorrectionLevel} representing the encoded error correction level + */ + public static ErrorCorrectionLevel ForBits(int bits) { + if (bits < 0 || bits >= FOR_BITS.Length) { + throw new IndexOutOfRangeException(); + } + return FOR_BITS[bits]; + } + } +} diff --git a/src/iTextSharp.LGPLv2.Core.FunctionalTests/QRCode.Apache.License/qrcode/FormatInformation.cs b/src/iTextSharp.LGPLv2.Core.FunctionalTests/QRCode.Apache.License/qrcode/FormatInformation.cs new file mode 100644 index 0000000..9e58a9b --- /dev/null +++ b/src/iTextSharp.LGPLv2.Core.FunctionalTests/QRCode.Apache.License/qrcode/FormatInformation.cs @@ -0,0 +1,175 @@ +using System; +/* + * Copyright 2007 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +namespace iTextSharp.text.pdf.qrcode { + + /** + *

Encapsulates a QR Code's format information, including the data mask used and + * error correction level.

+ * + * @author Sean Owen + * @see ErrorCorrectionLevel + */ + public sealed class FormatInformation { + + private const int FORMAT_INFO_MASK_QR = 0x5412; + + /** + * See ISO 18004:2006, Annex C, Table C.1 + */ + private static readonly int[][] FORMAT_INFO_DECODE_LOOKUP = { + new int[]{0x5412, 0x00}, + new int[]{0x5125, 0x01}, + new int[]{0x5E7C, 0x02}, + new int[]{0x5B4B, 0x03}, + new int[]{0x45F9, 0x04}, + new int[]{0x40CE, 0x05}, + new int[]{0x4F97, 0x06}, + new int[]{0x4AA0, 0x07}, + new int[]{0x77C4, 0x08}, + new int[]{0x72F3, 0x09}, + new int[]{0x7DAA, 0x0A}, + new int[]{0x789D, 0x0B}, + new int[]{0x662F, 0x0C}, + new int[]{0x6318, 0x0D}, + new int[]{0x6C41, 0x0E}, + new int[]{0x6976, 0x0F}, + new int[]{0x1689, 0x10}, + new int[]{0x13BE, 0x11}, + new int[]{0x1CE7, 0x12}, + new int[]{0x19D0, 0x13}, + new int[]{0x0762, 0x14}, + new int[]{0x0255, 0x15}, + new int[]{0x0D0C, 0x16}, + new int[]{0x083B, 0x17}, + new int[]{0x355F, 0x18}, + new int[]{0x3068, 0x19}, + new int[]{0x3F31, 0x1A}, + new int[]{0x3A06, 0x1B}, + new int[]{0x24B4, 0x1C}, + new int[]{0x2183, 0x1D}, + new int[]{0x2EDA, 0x1E}, + new int[]{0x2BED, 0x1F} + }; + + /** + * Offset i holds the number of 1 bits in the binary representation of i + */ + private static readonly int[] BITS_SET_IN_HALF_BYTE = + { 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4 }; + + private ErrorCorrectionLevel errorCorrectionLevel; + private byte dataMask; + + private FormatInformation(int formatInfo) { + // Bits 3,4 + errorCorrectionLevel = ErrorCorrectionLevel.ForBits((formatInfo >> 3) & 0x03); + // Bottom 3 bits + dataMask = (byte)(formatInfo & 0x07); + } + + public static int NumBitsDiffering(int a, int b) { + a ^= b; // a now has a 1 bit exactly where its bit differs with b's + // Count bits set quickly with a series of lookups: + return BITS_SET_IN_HALF_BYTE[a & 0x0F] + + BITS_SET_IN_HALF_BYTE[(a >> 4 & 0x0F)] + + BITS_SET_IN_HALF_BYTE[(a >> 8 & 0x0F)] + + BITS_SET_IN_HALF_BYTE[(a >> 12 & 0x0F)] + + BITS_SET_IN_HALF_BYTE[(a >> 16 & 0x0F)] + + BITS_SET_IN_HALF_BYTE[(a >> 20 & 0x0F)] + + BITS_SET_IN_HALF_BYTE[(a >> 24 & 0x0F)] + + BITS_SET_IN_HALF_BYTE[(a >> 28 & 0x0F)]; + } + + /** + * @param maskedFormatInfo1 format info indicator, with mask still applied + * @param maskedFormatInfo2 second copy of same info; both are checked at the same time + * to establish best match + * @return information about the format it specifies, or null + * if doesn't seem to match any known pattern + */ + public static FormatInformation DecodeFormatInformation(int maskedFormatInfo1, int maskedFormatInfo2) { + FormatInformation formatInfo = DoDecodeFormatInformation(maskedFormatInfo1, maskedFormatInfo2); + if (formatInfo != null) { + return formatInfo; + } + // Should return null, but, some QR codes apparently + // do not mask this info. Try again by actually masking the pattern + // first + return DoDecodeFormatInformation(maskedFormatInfo1 ^ FORMAT_INFO_MASK_QR, + maskedFormatInfo2 ^ FORMAT_INFO_MASK_QR); + } + + private static FormatInformation DoDecodeFormatInformation(int maskedFormatInfo1, int maskedFormatInfo2) { + // Find the int in FORMAT_INFO_DECODE_LOOKUP with fewest bits differing + int bestDifference = int.MaxValue; + int bestFormatInfo = 0; + for (int i = 0; i < FORMAT_INFO_DECODE_LOOKUP.GetLength(0); i++) { + int[] decodeInfo = FORMAT_INFO_DECODE_LOOKUP[i]; + int targetInfo = decodeInfo[0]; + if (targetInfo == maskedFormatInfo1 || targetInfo == maskedFormatInfo2) { + // Found an exact match + return new FormatInformation(decodeInfo[1]); + } + int bitsDifference = NumBitsDiffering(maskedFormatInfo1, targetInfo); + if (bitsDifference < bestDifference) { + bestFormatInfo = decodeInfo[1]; + bestDifference = bitsDifference; + } + if (maskedFormatInfo1 != maskedFormatInfo2) { + // also try the other option + bitsDifference = NumBitsDiffering(maskedFormatInfo2, targetInfo); + if (bitsDifference < bestDifference) { + bestFormatInfo = decodeInfo[1]; + bestDifference = bitsDifference; + } + } + } + // Hamming distance of the 32 masked codes is 7, by construction, so <= 3 bits + // differing means we found a match + if (bestDifference <= 3) { + return new FormatInformation(bestFormatInfo); + } + return null; + } + + public ErrorCorrectionLevel GetErrorCorrectionLevel() { + return errorCorrectionLevel; + } + + public byte GetDataMask() { + return dataMask; + } + + public int HashCode() { + return (errorCorrectionLevel.Ordinal() << 3) | (int)dataMask; + } + + public override int GetHashCode() { + return base.GetHashCode(); + } + + public override bool Equals(Object o) { + if (!(o is FormatInformation)) { + return false; + } + FormatInformation other = (FormatInformation)o; + return this.errorCorrectionLevel == other.errorCorrectionLevel && + this.dataMask == other.dataMask; + } + } +} diff --git a/src/iTextSharp.LGPLv2.Core.FunctionalTests/QRCode.Apache.License/qrcode/GF256.cs b/src/iTextSharp.LGPLv2.Core.FunctionalTests/QRCode.Apache.License/qrcode/GF256.cs new file mode 100644 index 0000000..1a05405 --- /dev/null +++ b/src/iTextSharp.LGPLv2.Core.FunctionalTests/QRCode.Apache.License/qrcode/GF256.cs @@ -0,0 +1,143 @@ +using System; +/* + * Copyright 2007 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +namespace iTextSharp.text.pdf.qrcode { + + /** + *

This class contains utility methods for performing mathematical operations over + * the Galois Field GF(256). Operations use a given primitive polynomial in calculations.

+ * + *

Throughout this package, elements of GF(256) are represented as an int + * for convenience and speed (but at the cost of memory). + * Only the bottom 8 bits are really used.

+ * + * @author Sean Owen + */ + public sealed class GF256 { + + public static readonly GF256 QR_CODE_FIELD = new GF256(0x011D); // x^8 + x^4 + x^3 + x^2 + 1 + public static readonly GF256 DATA_MATRIX_FIELD = new GF256(0x012D); // x^8 + x^5 + x^3 + x^2 + 1 + + private int[] expTable; + private int[] logTable; + private GF256Poly zero; + private GF256Poly one; + + /** + * Create a representation of GF(256) using the given primitive polynomial. + * + * @param primitive irreducible polynomial whose coefficients are represented by + * the bits of an int, where the least-significant bit represents the constant + * coefficient + */ + private GF256(int primitive) { + expTable = new int[256]; + logTable = new int[256]; + int x = 1; + for (int i = 0; i < 256; i++) { + expTable[i] = x; + x <<= 1; // x = x * 2; we're assuming the generator alpha is 2 + if (x >= 0x100) { + x ^= primitive; + } + } + for (int i = 0; i < 255; i++) { + logTable[expTable[i]] = i; + } + // logTable[0] == 0 but this should never be used + zero = new GF256Poly(this, new int[] { 0 }); + one = new GF256Poly(this, new int[] { 1 }); + } + + internal GF256Poly GetZero() { + return zero; + } + + internal GF256Poly GetOne() { + return one; + } + + /** + * @return the monomial representing coefficient * x^degree + */ + internal GF256Poly BuildMonomial(int degree, int coefficient) { + if (degree < 0) { + throw new ArgumentException(); + } + if (coefficient == 0) { + return zero; + } + int[] coefficients = new int[degree + 1]; + coefficients[0] = coefficient; + return new GF256Poly(this, coefficients); + } + + /** + * Implements both addition and subtraction -- they are the same in GF(256). + * + * @return sum/difference of a and b + */ + internal static int AddOrSubtract(int a, int b) { + return a ^ b; + } + + /** + * @return 2 to the power of a in GF(256) + */ + internal int Exp(int a) { + return expTable[a]; + } + + /** + * @return base 2 log of a in GF(256) + */ + internal int Log(int a) { + if (a == 0) { + throw new ArgumentException(); + } + return logTable[a]; + } + + /** + * @return multiplicative inverse of a + */ + internal int Inverse(int a) { + if (a == 0) { + throw new ArithmeticException(); + } + return expTable[255 - logTable[a]]; + } + + /** + * @param a + * @param b + * @return product of a and b in GF(256) + */ + internal int Multiply(int a, int b) { + if (a == 0 || b == 0) { + return 0; + } + if (a == 1) { + return b; + } + if (b == 1) { + return a; + } + return expTable[(logTable[a] + logTable[b]) % 255]; + } + } +} diff --git a/src/iTextSharp.LGPLv2.Core.FunctionalTests/QRCode.Apache.License/qrcode/GF256Poly.cs b/src/iTextSharp.LGPLv2.Core.FunctionalTests/QRCode.Apache.License/qrcode/GF256Poly.cs new file mode 100644 index 0000000..afb92a4 --- /dev/null +++ b/src/iTextSharp.LGPLv2.Core.FunctionalTests/QRCode.Apache.License/qrcode/GF256Poly.cs @@ -0,0 +1,271 @@ +using System; +using System.Text; +/* + * Copyright 2007 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +namespace iTextSharp.text.pdf.qrcode { + + /** + *

Represents a polynomial whose coefficients are elements of GF(256). + * Instances of this class are immutable.

+ * + *

Much credit is due to William Rucklidge since portions of this code are an indirect + * port of his C++ Reed-Solomon implementation.

+ * + * @author Sean Owen + */ + internal sealed class GF256Poly { + + private GF256 field; + private int[] coefficients; + + /** + * @param field the {@link GF256} instance representing the field to use + * to perform computations + * @param coefficients coefficients as ints representing elements of GF(256), arranged + * from most significant (highest-power term) coefficient to least significant + * @throws IllegalArgumentException if argument is null or empty, + * or if leading coefficient is 0 and this is not a + * constant polynomial (that is, it is not the monomial "0") + */ + internal GF256Poly(GF256 field, int[] coefficients) { + if (coefficients == null || coefficients.Length == 0) { + throw new ArgumentException(); + } + this.field = field; + int coefficientsLength = coefficients.Length; + if (coefficientsLength > 1 && coefficients[0] == 0) { + // Leading term must be non-zero for anything except the constant polynomial "0" + int firstNonZero = 1; + while (firstNonZero < coefficientsLength && coefficients[firstNonZero] == 0) { + firstNonZero++; + } + if (firstNonZero == coefficientsLength) { + this.coefficients = field.GetZero().coefficients; + } + else { + this.coefficients = new int[coefficientsLength - firstNonZero]; + System.Array.Copy(coefficients, + firstNonZero, + this.coefficients, + 0, + this.coefficients.Length); + } + } + else { + this.coefficients = coefficients; + } + } + + internal int[] GetCoefficients() { + return coefficients; + } + + /** + * @return degree of this polynomial + */ + internal int GetDegree() { + return coefficients.Length - 1; + } + + /** + * @return true iff this polynomial is the monomial "0" + */ + internal bool IsZero() { + return coefficients[0] == 0; + } + + /** + * @return coefficient of x^degree term in this polynomial + */ + internal int GetCoefficient(int degree) { + return coefficients[coefficients.Length - 1 - degree]; + } + + /** + * @return evaluation of this polynomial at a given point + */ + internal int EvaluateAt(int a) { + if (a == 0) { + // Just return the x^0 coefficient + return GetCoefficient(0); + } + int size = coefficients.Length; + if (a == 1) { + // Just the sum of the coefficients + int result2 = 0; + for (int i = 0; i < size; i++) { + result2 = GF256.AddOrSubtract(result2, coefficients[i]); + } + return result2; + } + int result = coefficients[0]; + for (int i = 1; i < size; i++) { + result = GF256.AddOrSubtract(field.Multiply(a, result), coefficients[i]); + } + return result; + } + + internal GF256Poly AddOrSubtract(GF256Poly other) { + if (!field.Equals(other.field)) { + throw new ArgumentException("GF256Polys do not have same GF256 field"); + } + if (IsZero()) { + return other; + } + if (other.IsZero()) { + return this; + } + + int[] smallerCoefficients = this.coefficients; + int[] largerCoefficients = other.coefficients; + if (smallerCoefficients.Length > largerCoefficients.Length) { + int[] temp = smallerCoefficients; + smallerCoefficients = largerCoefficients; + largerCoefficients = temp; + } + int[] sumDiff = new int[largerCoefficients.Length]; + int lengthDiff = largerCoefficients.Length - smallerCoefficients.Length; + // Copy high-order terms only found in higher-degree polynomial's coefficients + System.Array.Copy(largerCoefficients, 0, sumDiff, 0, lengthDiff); + + for (int i = lengthDiff; i < largerCoefficients.Length; i++) { + sumDiff[i] = GF256.AddOrSubtract(smallerCoefficients[i - lengthDiff], largerCoefficients[i]); + } + + return new GF256Poly(field, sumDiff); + } + + internal GF256Poly Multiply(GF256Poly other) { + if (!field.Equals(other.field)) { + throw new ArgumentException("GF256Polys do not have same GF256 field"); + } + if (IsZero() || other.IsZero()) { + return field.GetZero(); + } + int[] aCoefficients = this.coefficients; + int aLength = aCoefficients.Length; + int[] bCoefficients = other.coefficients; + int bLength = bCoefficients.Length; + int[] product = new int[aLength + bLength - 1]; + for (int i = 0; i < aLength; i++) { + int aCoeff = aCoefficients[i]; + for (int j = 0; j < bLength; j++) { + product[i + j] = GF256.AddOrSubtract(product[i + j], + field.Multiply(aCoeff, bCoefficients[j])); + } + } + return new GF256Poly(field, product); + } + + internal GF256Poly Multiply(int scalar) { + if (scalar == 0) { + return field.GetZero(); + } + if (scalar == 1) { + return this; + } + int size = coefficients.Length; + int[] product = new int[size]; + for (int i = 0; i < size; i++) { + product[i] = field.Multiply(coefficients[i], scalar); + } + return new GF256Poly(field, product); + } + + internal GF256Poly MultiplyByMonomial(int degree, int coefficient) { + if (degree < 0) { + throw new ArgumentException(); + } + if (coefficient == 0) { + return field.GetZero(); + } + int size = coefficients.Length; + int[] product = new int[size + degree]; + for (int i = 0; i < size; i++) { + product[i] = field.Multiply(coefficients[i], coefficient); + } + return new GF256Poly(field, product); + } + + internal GF256Poly[] Divide(GF256Poly other) { + if (!field.Equals(other.field)) { + throw new ArgumentException("GF256Polys do not have same GF256 field"); + } + if (other.IsZero()) { + throw new DivideByZeroException("Divide by 0"); + } + + GF256Poly quotient = field.GetZero(); + GF256Poly remainder = this; + + int denominatorLeadingTerm = other.GetCoefficient(other.GetDegree()); + int inverseDenominatorLeadingTerm = field.Inverse(denominatorLeadingTerm); + + while (remainder.GetDegree() >= other.GetDegree() && !remainder.IsZero()) { + int degreeDifference = remainder.GetDegree() - other.GetDegree(); + int scale = field.Multiply(remainder.GetCoefficient(remainder.GetDegree()), inverseDenominatorLeadingTerm); + GF256Poly term = other.MultiplyByMonomial(degreeDifference, scale); + GF256Poly iterationQuotient = field.BuildMonomial(degreeDifference, scale); + quotient = quotient.AddOrSubtract(iterationQuotient); + remainder = remainder.AddOrSubtract(term); + } + + return new GF256Poly[] { quotient, remainder }; + } + + public override String ToString() { + StringBuilder result = new StringBuilder(8 * GetDegree()); + for (int degree = GetDegree(); degree >= 0; degree--) { + int coefficient = GetCoefficient(degree); + if (coefficient != 0) { + if (coefficient < 0) { + result.Append(" - "); + coefficient = -coefficient; + } + else { + if (result.Length > 0) { + result.Append(" + "); + } + } + if (degree == 0 || coefficient != 1) { + int alphaPower = field.Log(coefficient); + if (alphaPower == 0) { + result.Append('1'); + } + else if (alphaPower == 1) { + result.Append('a'); + } + else { + result.Append("a^"); + result.Append(alphaPower); + } + } + if (degree != 0) { + if (degree == 1) { + result.Append('x'); + } + else { + result.Append("x^"); + result.Append(degree); + } + } + } + } + return result.ToString(); + } + } +} diff --git a/src/iTextSharp.LGPLv2.Core.FunctionalTests/QRCode.Apache.License/qrcode/MaskUtil.cs b/src/iTextSharp.LGPLv2.Core.FunctionalTests/QRCode.Apache.License/qrcode/MaskUtil.cs new file mode 100644 index 0000000..f399be7 --- /dev/null +++ b/src/iTextSharp.LGPLv2.Core.FunctionalTests/QRCode.Apache.License/qrcode/MaskUtil.cs @@ -0,0 +1,220 @@ +using System; +/* + * Copyright 2008 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +namespace iTextSharp.text.pdf.qrcode { + + /** + * @author satorux@google.com (Satoru Takabayashi) - creator + * @author dswitkin@google.com (Daniel Switkin) - ported from C++ + */ + public sealed class MaskUtil { + + private MaskUtil() { + // do nothing + } + + // Apply mask penalty rule 1 and return the penalty. Find repetitive cells with the same color and + // give penalty to them. Example: 00000 or 11111. + public static int ApplyMaskPenaltyRule1(ByteMatrix matrix) { + return ApplyMaskPenaltyRule1Internal(matrix, true) + ApplyMaskPenaltyRule1Internal(matrix, false); + } + + // Apply mask penalty rule 2 and return the penalty. Find 2x2 blocks with the same color and give + // penalty to them. + public static int ApplyMaskPenaltyRule2(ByteMatrix matrix) { + int penalty = 0; + sbyte[][] array = matrix.GetArray(); + int width = matrix.GetWidth(); + int height = matrix.GetHeight(); + for (int y = 0; y < height - 1; ++y) { + for (int x = 0; x < width - 1; ++x) { + int value = array[y][x]; + if (value == array[y][x + 1] && value == array[y + 1][x] && value == array[y + 1][x + 1]) { + penalty += 3; + } + } + } + return penalty; + } + + // Apply mask penalty rule 3 and return the penalty. Find consecutive cells of 00001011101 or + // 10111010000, and give penalty to them. If we find patterns like 000010111010000, we give + // penalties twice (i.e. 40 * 2). + public static int ApplyMaskPenaltyRule3(ByteMatrix matrix) { + int penalty = 0; + sbyte[][] array = matrix.GetArray(); + int width = matrix.GetWidth(); + int height = matrix.GetHeight(); + for (int y = 0; y < height; ++y) { + for (int x = 0; x < width; ++x) { + // Tried to simplify following conditions but failed. + if (x + 6 < width && + array[y][x] == 1 && + array[y][x + 1] == 0 && + array[y][x + 2] == 1 && + array[y][x + 3] == 1 && + array[y][x + 4] == 1 && + array[y][x + 5] == 0 && + array[y][x + 6] == 1 && + ((x + 10 < width && + array[y][x + 7] == 0 && + array[y][x + 8] == 0 && + array[y][x + 9] == 0 && + array[y][x + 10] == 0) || + (x - 4 >= 0 && + array[y][x - 1] == 0 && + array[y][x - 2] == 0 && + array[y][x - 3] == 0 && + array[y][x - 4] == 0))) { + penalty += 40; + } + if (y + 6 < height && + array[y][x] == 1 && + array[y + 1][x] == 0 && + array[y + 2][x] == 1 && + array[y + 3][x] == 1 && + array[y + 4][x] == 1 && + array[y + 5][x] == 0 && + array[y + 6][x] == 1 && + ((y + 10 < height && + array[y + 7][x] == 0 && + array[y + 8][x] == 0 && + array[y + 9][x] == 0 && + array[y + 10][x] == 0) || + (y - 4 >= 0 && + array[y - 1][x] == 0 && + array[y - 2][x] == 0 && + array[y - 3][x] == 0 && + array[y - 4][x] == 0))) { + penalty += 40; + } + } + } + return penalty; + } + + // Apply mask penalty rule 4 and return the penalty. Calculate the ratio of dark cells and give + // penalty if the ratio is far from 50%. It gives 10 penalty for 5% distance. Examples: + // - 0% => 100 + // - 40% => 20 + // - 45% => 10 + // - 50% => 0 + // - 55% => 10 + // - 55% => 20 + // - 100% => 100 + public static int ApplyMaskPenaltyRule4(ByteMatrix matrix) { + int numDarkCells = 0; + sbyte[][] array = matrix.GetArray(); + int width = matrix.GetWidth(); + int height = matrix.GetHeight(); + for (int y = 0; y < height; ++y) { + for (int x = 0; x < width; ++x) { + if (array[y][x] == 1) { + numDarkCells += 1; + } + } + } + int numTotalCells = matrix.GetHeight() * matrix.GetWidth(); + double darkRatio = (double)numDarkCells / numTotalCells; + return Math.Abs((int)(darkRatio * 100 - 50)) / 5 * 10; + } + + // Return the mask bit for "getMaskPattern" at "x" and "y". See 8.8 of JISX0510:2004 for mask + // pattern conditions. + public static bool GetDataMaskBit(int maskPattern, int x, int y) { + if (!QRCode.IsValidMaskPattern(maskPattern)) { + throw new ArgumentException("Invalid mask pattern"); + } + int intermediate, temp; + switch (maskPattern) { + case 0: + intermediate = (y + x) & 0x1; + break; + case 1: + intermediate = y & 0x1; + break; + case 2: + intermediate = x % 3; + break; + case 3: + intermediate = (y + x) % 3; + break; + case 4: + intermediate = ((y >> 1) + (x / 3)) & 0x1; + break; + case 5: + temp = y * x; + intermediate = (temp & 0x1) + (temp % 3); + break; + case 6: + temp = y * x; + intermediate = (((temp & 0x1) + (temp % 3)) & 0x1); + break; + case 7: + temp = y * x; + intermediate = (((temp % 3) + ((y + x) & 0x1)) & 0x1); + break; + default: + throw new ArgumentException("Invalid mask pattern: " + maskPattern); + } + return intermediate == 0; + } + + // Helper function for applyMaskPenaltyRule1. We need this for doing this calculation in both + // vertical and horizontal orders respectively. + private static int ApplyMaskPenaltyRule1Internal(ByteMatrix matrix, bool isHorizontal) { + int penalty = 0; + int numSameBitCells = 0; + int prevBit = -1; + // Horizontal mode: + // for (int i = 0; i < matrix.Height(); ++i) { + // for (int j = 0; j < matrix.Width(); ++j) { + // int bit = matrix.Get(i, j); + // Vertical mode: + // for (int i = 0; i < matrix.Width(); ++i) { + // for (int j = 0; j < matrix.Height(); ++j) { + // int bit = matrix.Get(j, i); + int iLimit = isHorizontal ? matrix.GetHeight() : matrix.GetWidth(); + int jLimit = isHorizontal ? matrix.GetWidth() : matrix.GetHeight(); + sbyte[][] array = matrix.GetArray(); + for (int i = 0; i < iLimit; ++i) { + for (int j = 0; j < jLimit; ++j) { + int bit = isHorizontal ? array[i][j] : array[j][i]; + if (bit == prevBit) { + numSameBitCells += 1; + // Found five repetitive cells with the same color (bit). + // We'll give penalty of 3. + if (numSameBitCells == 5) { + penalty += 3; + } + else if (numSameBitCells > 5) { + // After five repetitive cells, we'll add the penalty one + // by one. + penalty += 1; + } + } + else { + numSameBitCells = 1; // Include the cell itself. + prevBit = bit; + } + } + numSameBitCells = 0; // Clear at each row/column. + } + return penalty; + } + } +} diff --git a/src/iTextSharp.LGPLv2.Core.FunctionalTests/QRCode.Apache.License/qrcode/MatrixUtil.cs b/src/iTextSharp.LGPLv2.Core.FunctionalTests/QRCode.Apache.License/qrcode/MatrixUtil.cs new file mode 100644 index 0000000..0f2f4bb --- /dev/null +++ b/src/iTextSharp.LGPLv2.Core.FunctionalTests/QRCode.Apache.License/qrcode/MatrixUtil.cs @@ -0,0 +1,520 @@ +using System; +/* + * Copyright 2008 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +namespace iTextSharp.text.pdf.qrcode { + + /** + * @author satorux@google.com (Satoru Takabayashi) - creator + * @author dswitkin@google.com (Daniel Switkin) - ported from C++ + */ + public sealed class MatrixUtil { + + private MatrixUtil() { + // do nothing + } + + private static readonly int[][] POSITION_DETECTION_PATTERN = { + new int[]{1, 1, 1, 1, 1, 1, 1}, + new int[]{1, 0, 0, 0, 0, 0, 1}, + new int[]{1, 0, 1, 1, 1, 0, 1}, + new int[]{1, 0, 1, 1, 1, 0, 1}, + new int[]{1, 0, 1, 1, 1, 0, 1}, + new int[]{1, 0, 0, 0, 0, 0, 1}, + new int[]{1, 1, 1, 1, 1, 1, 1} + }; + + private static readonly int[][] HORIZONTAL_SEPARATION_PATTERN = { + new int[]{0, 0, 0, 0, 0, 0, 0, 0} + }; + + private static readonly int[][] VERTICAL_SEPARATION_PATTERN = { + new int[]{0}, new int[]{0}, new int[]{0}, new int[]{0}, new int[]{0}, new int[]{0}, new int[]{0} + }; + + private static readonly int[][] POSITION_ADJUSTMENT_PATTERN = { + new int[]{1, 1, 1, 1, 1}, + new int[]{1, 0, 0, 0, 1}, + new int[]{1, 0, 1, 0, 1}, + new int[]{1, 0, 0, 0, 1}, + new int[]{1, 1, 1, 1, 1} + }; + + // From Appendix E. Table 1, JIS0510X:2004 (p 71). The table was double-checked by komatsu. + private static readonly int[][] POSITION_ADJUSTMENT_PATTERN_COORDINATE_TABLE = { + new int[]{-1, -1, -1, -1, -1, -1, -1}, // Version 1 + new int[]{ 6, 18, -1, -1, -1, -1, -1}, // Version 2 + new int[]{ 6, 22, -1, -1, -1, -1, -1}, // Version 3 + new int[]{ 6, 26, -1, -1, -1, -1, -1}, // Version 4 + new int[]{ 6, 30, -1, -1, -1, -1, -1}, // Version 5 + new int[]{ 6, 34, -1, -1, -1, -1, -1}, // Version 6 + new int[]{ 6, 22, 38, -1, -1, -1, -1}, // Version 7 + new int[]{ 6, 24, 42, -1, -1, -1, -1}, // Version 8 + new int[]{ 6, 26, 46, -1, -1, -1, -1}, // Version 9 + new int[]{ 6, 28, 50, -1, -1, -1, -1}, // Version 10 + new int[]{ 6, 30, 54, -1, -1, -1, -1}, // Version 11 + new int[]{ 6, 32, 58, -1, -1, -1, -1}, // Version 12 + new int[]{ 6, 34, 62, -1, -1, -1, -1}, // Version 13 + new int[]{ 6, 26, 46, 66, -1, -1, -1}, // Version 14 + new int[]{ 6, 26, 48, 70, -1, -1, -1}, // Version 15 + new int[]{ 6, 26, 50, 74, -1, -1, -1}, // Version 16 + new int[]{ 6, 30, 54, 78, -1, -1, -1}, // Version 17 + new int[]{ 6, 30, 56, 82, -1, -1, -1}, // Version 18 + new int[]{ 6, 30, 58, 86, -1, -1, -1}, // Version 19 + new int[]{ 6, 34, 62, 90, -1, -1, -1}, // Version 20 + new int[]{ 6, 28, 50, 72, 94, -1, -1}, // Version 21 + new int[]{ 6, 26, 50, 74, 98, -1, -1}, // Version 22 + new int[]{ 6, 30, 54, 78, 102, -1, -1}, // Version 23 + new int[]{ 6, 28, 54, 80, 106, -1, -1}, // Version 24 + new int[]{ 6, 32, 58, 84, 110, -1, -1}, // Version 25 + new int[]{ 6, 30, 58, 86, 114, -1, -1}, // Version 26 + new int[]{ 6, 34, 62, 90, 118, -1, -1}, // Version 27 + new int[]{ 6, 26, 50, 74, 98, 122, -1}, // Version 28 + new int[]{ 6, 30, 54, 78, 102, 126, -1}, // Version 29 + new int[]{ 6, 26, 52, 78, 104, 130, -1}, // Version 30 + new int[]{ 6, 30, 56, 82, 108, 134, -1}, // Version 31 + new int[]{ 6, 34, 60, 86, 112, 138, -1}, // Version 32 + new int[]{ 6, 30, 58, 86, 114, 142, -1}, // Version 33 + new int[]{ 6, 34, 62, 90, 118, 146, -1}, // Version 34 + new int[]{ 6, 30, 54, 78, 102, 126, 150}, // Version 35 + new int[]{ 6, 24, 50, 76, 102, 128, 154}, // Version 36 + new int[]{ 6, 28, 54, 80, 106, 132, 158}, // Version 37 + new int[]{ 6, 32, 58, 84, 110, 136, 162}, // Version 38 + new int[]{ 6, 26, 54, 82, 110, 138, 166}, // Version 39 + new int[]{ 6, 30, 58, 86, 114, 142, 170} // Version 40 + }; + + // Type info cells at the left top corner. + private static readonly int[][] TYPE_INFO_COORDINATES = { + new int[]{8, 0}, + new int[]{8, 1}, + new int[]{8, 2}, + new int[]{8, 3}, + new int[]{8, 4}, + new int[]{8, 5}, + new int[]{8, 7}, + new int[]{8, 8}, + new int[]{7, 8}, + new int[]{5, 8}, + new int[]{4, 8}, + new int[]{3, 8}, + new int[]{2, 8}, + new int[]{1, 8}, + new int[]{0, 8} + }; + + // From Appendix D in JISX0510:2004 (p. 67) + private const int VERSION_INFO_POLY = 0x1f25; // 1 1111 0010 0101 + + // From Appendix C in JISX0510:2004 (p.65). + private const int TYPE_INFO_POLY = 0x537; + private const int TYPE_INFO_MASK_PATTERN = 0x5412; + + // Set all cells to -1. -1 means that the cell is empty (not set yet). + // + // JAVAPORT: We shouldn't need to do this at all. The code should be rewritten to begin encoding + // with the ByteMatrix initialized all to zero. + public static void ClearMatrix(ByteMatrix matrix) { + matrix.Clear((sbyte)-1); + } + + // Build 2D matrix of QR Code from "dataBits" with "ecLevel", "version" and "getMaskPattern". On + // success, store the result in "matrix" and return true. + public static void BuildMatrix(BitVector dataBits, ErrorCorrectionLevel ecLevel, int version, + int maskPattern, ByteMatrix matrix) { + ClearMatrix(matrix); + EmbedBasicPatterns(version, matrix); + // Type information appear with any version. + EmbedTypeInfo(ecLevel, maskPattern, matrix); + // Version info appear if version >= 7. + MaybeEmbedVersionInfo(version, matrix); + // Data should be embedded at end. + EmbedDataBits(dataBits, maskPattern, matrix); + } + + // Embed basic patterns. On success, modify the matrix and return true. + // The basic patterns are: + // - Position detection patterns + // - Timing patterns + // - Dark dot at the left bottom corner + // - Position adjustment patterns, if need be + public static void EmbedBasicPatterns(int version, ByteMatrix matrix) { + // Let's get started with embedding big squares at corners. + EmbedPositionDetectionPatternsAndSeparators(matrix); + // Then, embed the dark dot at the left bottom corner. + EmbedDarkDotAtLeftBottomCorner(matrix); + + // Position adjustment patterns appear if version >= 2. + MaybeEmbedPositionAdjustmentPatterns(version, matrix); + // Timing patterns should be embedded after position adj. patterns. + EmbedTimingPatterns(matrix); + } + + // Embed type information. On success, modify the matrix. + public static void EmbedTypeInfo(ErrorCorrectionLevel ecLevel, int maskPattern, ByteMatrix matrix) { + BitVector typeInfoBits = new BitVector(); + MakeTypeInfoBits(ecLevel, maskPattern, typeInfoBits); + + for (int i = 0; i < typeInfoBits.Size(); ++i) { + // Place bits in LSB to MSB order. LSB (least significant bit) is the last value in + // "typeInfoBits". + int bit = typeInfoBits.At(typeInfoBits.Size() - 1 - i); + + // Type info bits at the left top corner. See 8.9 of JISX0510:2004 (p.46). + int x1 = TYPE_INFO_COORDINATES[i][0]; + int y1 = TYPE_INFO_COORDINATES[i][1]; + matrix.Set(x1, y1, bit); + + if (i < 8) { + // Right top corner. + int x2 = matrix.GetWidth() - i - 1; + int y2 = 8; + matrix.Set(x2, y2, bit); + } + else { + // Left bottom corner. + int x2 = 8; + int y2 = matrix.GetHeight() - 7 + (i - 8); + matrix.Set(x2, y2, bit); + } + } + } + + // Embed version information if need be. On success, modify the matrix and return true. + // See 8.10 of JISX0510:2004 (p.47) for how to embed version information. + public static void MaybeEmbedVersionInfo(int version, ByteMatrix matrix) { + if (version < 7) { // Version info is necessary if version >= 7. + return; // Don't need version info. + } + BitVector versionInfoBits = new BitVector(); + MakeVersionInfoBits(version, versionInfoBits); + + int bitIndex = 6 * 3 - 1; // It will decrease from 17 to 0. + for (int i = 0; i < 6; ++i) { + for (int j = 0; j < 3; ++j) { + // Place bits in LSB (least significant bit) to MSB order. + int bit = versionInfoBits.At(bitIndex); + bitIndex--; + // Left bottom corner. + matrix.Set(i, matrix.GetHeight() - 11 + j, bit); + // Right bottom corner. + matrix.Set(matrix.GetHeight() - 11 + j, i, bit); + } + } + } + + // Embed "dataBits" using "getMaskPattern". On success, modify the matrix and return true. + // For debugging purposes, it skips masking process if "getMaskPattern" is -1. + // See 8.7 of JISX0510:2004 (p.38) for how to embed data bits. + public static void EmbedDataBits(BitVector dataBits, int maskPattern, ByteMatrix matrix) { + int bitIndex = 0; + int direction = -1; + // Start from the right bottom cell. + int x = matrix.GetWidth() - 1; + int y = matrix.GetHeight() - 1; + while (x > 0) { + // Skip the vertical timing pattern. + if (x == 6) { + x -= 1; + } + while (y >= 0 && y < matrix.GetHeight()) { + for (int i = 0; i < 2; ++i) { + int xx = x - i; + // Skip the cell if it's not empty. + if (!IsEmpty(matrix.Get(xx, y))) { + continue; + } + int bit; + if (bitIndex < dataBits.Size()) { + bit = dataBits.At(bitIndex); + ++bitIndex; + } + else { + // Padding bit. If there is no bit left, we'll fill the left cells with 0, as described + // in 8.4.9 of JISX0510:2004 (p. 24). + bit = 0; + } + + // Skip masking if mask_pattern is -1. + if (maskPattern != -1) { + if (MaskUtil.GetDataMaskBit(maskPattern, xx, y)) { + bit ^= 0x1; + } + } + matrix.Set(xx, y, bit); + } + y += direction; + } + direction = -direction; // Reverse the direction. + y += direction; + x -= 2; // Move to the left. + } + // All bits should be consumed. + if (bitIndex != dataBits.Size()) { + throw new WriterException("Not all bits consumed: " + bitIndex + '/' + dataBits.Size()); + } + } + + // Return the position of the most significant bit set (to one) in the "value". The most + // significant bit is position 32. If there is no bit set, return 0. Examples: + // - FindMSBSet(0) => 0 + // - FindMSBSet(1) => 1 + // - FindMSBSet(255) => 8 + public static int FindMSBSet(int value) { + uint val = (uint)value; + int numDigits = 0; + while (val != 0) { + val >>= 1; + ++numDigits; + } + return numDigits; + } + + // Calculate BCH (Bose-Chaudhuri-Hocquenghem) code for "value" using polynomial "poly". The BCH + // code is used for encoding type information and version information. + // Example: Calculation of version information of 7. + // F(x) is created from 7. + // - 7 = 000111 in 6 bits + // - F(x) = x^2 + x^2 + x^1 + // G(x) is given by the standard (p. 67) + // - G(x) = x^12 + x^11 + x^10 + x^9 + x^8 + x^5 + x^2 + 1 + // Multiply F(x) by x^(18 - 6) + // - f'(x) = F(x) * x^(18 - 6) + // - f'(x) = x^14 + x^13 + x^12 + // Calculate the remainder of f'(x) / G(x) + // x^2 + // __________________________________________________ + // G(x) )x^14 + x^13 + x^12 + // x^14 + x^13 + x^12 + x^11 + x^10 + x^7 + x^4 + x^2 + // -------------------------------------------------- + // x^11 + x^10 + x^7 + x^4 + x^2 + // + // The remainder is x^11 + x^10 + x^7 + x^4 + x^2 + // Encode it in binary: 110010010100 + // The return value is 0xc94 (1100 1001 0100) + // + // Since all coefficients in the polynomials are 1 or 0, we can do the calculation by bit + // operations. We don't care if cofficients are positive or negative. + public static int CalculateBCHCode(int value, int poly) { + // If poly is "1 1111 0010 0101" (version info poly), msbSetInPoly is 13. We'll subtract 1 + // from 13 to make it 12. + int msbSetInPoly = FindMSBSet(poly); + value <<= msbSetInPoly - 1; + // Do the division business using exclusive-or operations. + while (FindMSBSet(value) >= msbSetInPoly) { + value ^= poly << (FindMSBSet(value) - msbSetInPoly); + } + // Now the "value" is the remainder (i.e. the BCH code) + return value; + } + + // Make bit vector of type information. On success, store the result in "bits" and return true. + // Encode error correction level and mask pattern. See 8.9 of + // JISX0510:2004 (p.45) for details. + public static void MakeTypeInfoBits(ErrorCorrectionLevel ecLevel, int maskPattern, BitVector bits) { + if (!QRCode.IsValidMaskPattern(maskPattern)) { + throw new WriterException("Invalid mask pattern"); + } + int typeInfo = (ecLevel.GetBits() << 3) | maskPattern; + bits.AppendBits(typeInfo, 5); + + int bchCode = CalculateBCHCode(typeInfo, TYPE_INFO_POLY); + bits.AppendBits(bchCode, 10); + + BitVector maskBits = new BitVector(); + maskBits.AppendBits(TYPE_INFO_MASK_PATTERN, 15); + bits.Xor(maskBits); + + if (bits.Size() != 15) { // Just in case. + throw new WriterException("should not happen but we got: " + bits.Size()); + } + } + + // Make bit vector of version information. On success, store the result in "bits" and return true. + // See 8.10 of JISX0510:2004 (p.45) for details. + public static void MakeVersionInfoBits(int version, BitVector bits) { + bits.AppendBits(version, 6); + int bchCode = CalculateBCHCode(version, VERSION_INFO_POLY); + bits.AppendBits(bchCode, 12); + + if (bits.Size() != 18) { // Just in case. + throw new WriterException("should not happen but we got: " + bits.Size()); + } + } + + // Check if "value" is empty. + private static bool IsEmpty(int value) { + return value == -1; + } + + // Check if "value" is valid. + private static bool IsValidValue(int value) { + return (value == -1 || // Empty. + value == 0 || // Light (white). + value == 1); // Dark (black). + } + + private static void EmbedTimingPatterns(ByteMatrix matrix) { + // -8 is for skipping position detection patterns (size 7), and two horizontal/vertical + // separation patterns (size 1). Thus, 8 = 7 + 1. + for (int i = 8; i < matrix.GetWidth() - 8; ++i) { + int bit = (i + 1) % 2; + // Horizontal line. + if (!IsValidValue(matrix.Get(i, 6))) { + throw new WriterException(); + } + if (IsEmpty(matrix.Get(i, 6))) { + matrix.Set(i, 6, bit); + } + // Vertical line. + if (!IsValidValue(matrix.Get(6, i))) { + throw new WriterException(); + } + if (IsEmpty(matrix.Get(6, i))) { + matrix.Set(6, i, bit); + } + } + } + + // Embed the lonely dark dot at left bottom corner. JISX0510:2004 (p.46) + private static void EmbedDarkDotAtLeftBottomCorner(ByteMatrix matrix) { + if (matrix.Get(8, matrix.GetHeight() - 8) == 0) { + throw new WriterException(); + } + matrix.Set(8, matrix.GetHeight() - 8, 1); + } + + private static void EmbedHorizontalSeparationPattern(int xStart, int yStart, + ByteMatrix matrix) { + // We know the width and height. + if (HORIZONTAL_SEPARATION_PATTERN[0].Length != 8 || HORIZONTAL_SEPARATION_PATTERN.GetLength(0) != 1) { + throw new WriterException("Bad horizontal separation pattern"); + } + for (int x = 0; x < 8; ++x) { + if (!IsEmpty(matrix.Get(xStart + x, yStart))) { + throw new WriterException(); + } + matrix.Set(xStart + x, yStart, HORIZONTAL_SEPARATION_PATTERN[0][x]); + } + } + + private static void EmbedVerticalSeparationPattern(int xStart, int yStart, + ByteMatrix matrix) { + // We know the width and height. + if (VERTICAL_SEPARATION_PATTERN[0].Length != 1 || VERTICAL_SEPARATION_PATTERN.GetLength(0) != 7) { + throw new WriterException("Bad vertical separation pattern"); + } + for (int y = 0; y < 7; ++y) { + if (!IsEmpty(matrix.Get(xStart, yStart + y))) { + throw new WriterException(); + } + matrix.Set(xStart, yStart + y, VERTICAL_SEPARATION_PATTERN[y][0]); + } + } + + // Note that we cannot unify the function with EmbedPositionDetectionPattern() despite they are + // almost identical, since we cannot write a function that takes 2D arrays in different sizes in + // C/C++. We should live with the fact. + private static void EmbedPositionAdjustmentPattern(int xStart, int yStart, + ByteMatrix matrix) { + // We know the width and height. + if (POSITION_ADJUSTMENT_PATTERN[0].Length != 5 || POSITION_ADJUSTMENT_PATTERN.GetLength(0) != 5) { + throw new WriterException("Bad position adjustment"); + } + for (int y = 0; y < 5; ++y) { + for (int x = 0; x < 5; ++x) { + if (!IsEmpty(matrix.Get(xStart + x, yStart + y))) { + throw new WriterException(); + } + matrix.Set(xStart + x, yStart + y, POSITION_ADJUSTMENT_PATTERN[y][x]); + } + } + } + + private static void EmbedPositionDetectionPattern(int xStart, int yStart, + ByteMatrix matrix) { + // We know the width and height. + if (POSITION_DETECTION_PATTERN[0].Length != 7 || POSITION_DETECTION_PATTERN.GetLength(0) != 7) { + throw new WriterException("Bad position detection pattern"); + } + for (int y = 0; y < 7; ++y) { + for (int x = 0; x < 7; ++x) { + if (!IsEmpty(matrix.Get(xStart + x, yStart + y))) { + throw new WriterException(); + } + matrix.Set(xStart + x, yStart + y, POSITION_DETECTION_PATTERN[y][x]); + } + } + } + + // Embed position detection patterns and surrounding vertical/horizontal separators. + private static void EmbedPositionDetectionPatternsAndSeparators(ByteMatrix matrix) { + // Embed three big squares at corners. + int pdpWidth = POSITION_DETECTION_PATTERN[0].Length; + // Left top corner. + EmbedPositionDetectionPattern(0, 0, matrix); + // Right top corner. + EmbedPositionDetectionPattern(matrix.GetWidth() - pdpWidth, 0, matrix); + // Left bottom corner. + EmbedPositionDetectionPattern(0, matrix.GetWidth() - pdpWidth, matrix); + + // Embed horizontal separation patterns around the squares. + int hspWidth = HORIZONTAL_SEPARATION_PATTERN[0].Length; + // Left top corner. + EmbedHorizontalSeparationPattern(0, hspWidth - 1, matrix); + // Right top corner. + EmbedHorizontalSeparationPattern(matrix.GetWidth() - hspWidth, + hspWidth - 1, matrix); + // Left bottom corner. + EmbedHorizontalSeparationPattern(0, matrix.GetWidth() - hspWidth, matrix); + + // Embed vertical separation patterns around the squares. + int vspSize = VERTICAL_SEPARATION_PATTERN.Length; + // Left top corner. + EmbedVerticalSeparationPattern(vspSize, 0, matrix); + // Right top corner. + EmbedVerticalSeparationPattern(matrix.GetHeight() - vspSize - 1, 0, matrix); + // Left bottom corner. + EmbedVerticalSeparationPattern(vspSize, matrix.GetHeight() - vspSize, + matrix); + } + + // Embed position adjustment patterns if need be. + private static void MaybeEmbedPositionAdjustmentPatterns(int version, ByteMatrix matrix) { + if (version < 2) { // The patterns appear if version >= 2 + return; + } + int index = version - 1; + int[] coordinates = POSITION_ADJUSTMENT_PATTERN_COORDINATE_TABLE[index]; + int numCoordinates = POSITION_ADJUSTMENT_PATTERN_COORDINATE_TABLE[index].Length; + for (int i = 0; i < numCoordinates; ++i) { + for (int j = 0; j < numCoordinates; ++j) { + int y = coordinates[i]; + int x = coordinates[j]; + if (x == -1 || y == -1) { + continue; + } + // If the cell is unset, we embed the position adjustment pattern here. + if (IsEmpty(matrix.Get(x, y))) { + // -2 is necessary since the x/y coordinates point to the center of the pattern, not the + // left top corner. + EmbedPositionAdjustmentPattern(x - 2, y - 2, matrix); + } + } + } + } + } +} diff --git a/src/iTextSharp.LGPLv2.Core.FunctionalTests/QRCode.Apache.License/qrcode/Mode.cs b/src/iTextSharp.LGPLv2.Core.FunctionalTests/QRCode.Apache.License/qrcode/Mode.cs new file mode 100644 index 0000000..49681ec --- /dev/null +++ b/src/iTextSharp.LGPLv2.Core.FunctionalTests/QRCode.Apache.License/qrcode/Mode.cs @@ -0,0 +1,115 @@ +using System; +/* + * Copyright 2007 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +namespace iTextSharp.text.pdf.qrcode { + + /** + *

See ISO 18004:2006, 6.4.1, Tables 2 and 3. This enum encapsulates the various modes in which + * data can be encoded to bits in the QR code standard.

+ * + * @author Sean Owen + */ + public sealed class Mode { + + // No, we can't use an enum here. J2ME doesn't support it. + + public static readonly Mode TERMINATOR = new Mode(new int[] { 0, 0, 0 }, 0x00, "TERMINATOR"); // Not really a mode... + public static readonly Mode NUMERIC = new Mode(new int[] { 10, 12, 14 }, 0x01, "NUMERIC"); + public static readonly Mode ALPHANUMERIC = new Mode(new int[] { 9, 11, 13 }, 0x02, "ALPHANUMERIC"); + public static readonly Mode STRUCTURED_APPEND = new Mode(new int[] { 0, 0, 0 }, 0x03, "STRUCTURED_APPEND"); // Not supported + public static readonly Mode BYTE = new Mode(new int[] { 8, 16, 16 }, 0x04, "BYTE"); + public static readonly Mode ECI = new Mode(null, 0x07, "ECI"); // character counts don't apply + public static readonly Mode KANJI = new Mode(new int[] { 8, 10, 12 }, 0x08, "KANJI"); + public static readonly Mode FNC1_FIRST_POSITION = new Mode(null, 0x05, "FNC1_FIRST_POSITION"); + public static readonly Mode FNC1_SECOND_POSITION = new Mode(null, 0x09, "FNC1_SECOND_POSITION"); + + private int[] characterCountBitsForVersions; + private int bits; + private String name; + + private Mode(int[] characterCountBitsForVersions, int bits, String name) { + this.characterCountBitsForVersions = characterCountBitsForVersions; + this.bits = bits; + this.name = name; + } + + /** + * @param bits four bits encoding a QR Code data mode + * @return {@link Mode} encoded by these bits + * @throws IllegalArgumentException if bits do not correspond to a known mode + */ + public static Mode ForBits(int bits) { + switch (bits) { + case 0x0: + return TERMINATOR; + case 0x1: + return NUMERIC; + case 0x2: + return ALPHANUMERIC; + case 0x3: + return STRUCTURED_APPEND; + case 0x4: + return BYTE; + case 0x5: + return FNC1_FIRST_POSITION; + case 0x7: + return ECI; + case 0x8: + return KANJI; + case 0x9: + return FNC1_SECOND_POSITION; + default: + throw new ArgumentException(); + } + } + + /** + * @param version version in question + * @return number of bits used, in this QR Code symbol {@link Version}, to encode the + * count of characters that will follow encoded in this {@link Mode} + */ + public int GetCharacterCountBits(Version version) { + if (characterCountBitsForVersions == null) { + throw new ArgumentException("Character count doesn't apply to this mode"); + } + int number = version.GetVersionNumber(); + int offset; + if (number <= 9) { + offset = 0; + } + else if (number <= 26) { + offset = 1; + } + else { + offset = 2; + } + return characterCountBitsForVersions[offset]; + } + + public int GetBits() { + return bits; + } + + public String GetName() { + return name; + } + + public override String ToString() { + return name; + } + } +} diff --git a/src/iTextSharp.LGPLv2.Core.FunctionalTests/QRCode.Apache.License/qrcode/QRCode.cs b/src/iTextSharp.LGPLv2.Core.FunctionalTests/QRCode.Apache.License/qrcode/QRCode.cs new file mode 100644 index 0000000..f5ce7ad --- /dev/null +++ b/src/iTextSharp.LGPLv2.Core.FunctionalTests/QRCode.Apache.License/qrcode/QRCode.cs @@ -0,0 +1,240 @@ +using System; +using System.Text; +/* + * Copyright 2008 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +namespace iTextSharp.text.pdf.qrcode { + + + /** + * @author satorux@google.com (Satoru Takabayashi) - creator + * @author dswitkin@google.com (Daniel Switkin) - ported from C++ + */ + public sealed class QRCode { + + public const int NUM_MASK_PATTERNS = 8; + + private Mode mode; + private ErrorCorrectionLevel ecLevel; + private int version; + private int matrixWidth; + private int maskPattern; + private int numTotalBytes; + private int numDataBytes; + private int numECBytes; + private int numRSBlocks; + private ByteMatrix matrix; + + public QRCode() { + mode = null; + ecLevel = null; + version = -1; + matrixWidth = -1; + maskPattern = -1; + numTotalBytes = -1; + numDataBytes = -1; + numECBytes = -1; + numRSBlocks = -1; + matrix = null; + } + + // Mode of the QR Code. + public Mode GetMode() { + return mode; + } + + // Error correction level of the QR Code. + public ErrorCorrectionLevel GetECLevel() { + return ecLevel; + } + + // Version of the QR Code. The bigger size, the bigger version. + public int GetVersion() { + return version; + } + + // ByteMatrix width of the QR Code. + public int GetMatrixWidth() { + return matrixWidth; + } + + // Mask pattern of the QR Code. + public int GetMaskPattern() { + return maskPattern; + } + + // Number of total bytes in the QR Code. + public int GetNumTotalBytes() { + return numTotalBytes; + } + + // Number of data bytes in the QR Code. + public int GetNumDataBytes() { + return numDataBytes; + } + + // Number of error correction bytes in the QR Code. + public int GetNumECBytes() { + return numECBytes; + } + + // Number of Reedsolomon blocks in the QR Code. + public int GetNumRSBlocks() { + return numRSBlocks; + } + + // ByteMatrix data of the QR Code. + public ByteMatrix GetMatrix() { + return matrix; + } + + + // Return the value of the module (cell) pointed by "x" and "y" in the matrix of the QR Code. They + // call cells in the matrix "modules". 1 represents a black cell, and 0 represents a white cell. + public int At(int x, int y) { + // The value must be zero or one. + int value = matrix.Get(x, y); + if (!(value == 0 || value == 1)) { + // this is really like an assert... not sure what better exception to use? + throw new ArgumentException("Bad value"); + } + return value; + } + + // Checks all the member variables are set properly. Returns true on success. Otherwise, returns + // false. + public bool IsValid() { + return + // First check if all version are not uninitialized. + mode != null && + ecLevel != null && + version != -1 && + matrixWidth != -1 && + maskPattern != -1 && + numTotalBytes != -1 && + numDataBytes != -1 && + numECBytes != -1 && + numRSBlocks != -1 && + // Then check them in other ways.. + IsValidMaskPattern(maskPattern) && + numTotalBytes == numDataBytes + numECBytes && + // ByteMatrix stuff. + matrix != null && + matrixWidth == matrix.GetWidth() && + // See 7.3.1 of JISX0510:2004 (p.5). + matrix.GetWidth() == matrix.GetHeight(); // Must be square. + } + + // Return debug String. + public override String ToString() { + StringBuilder result = new StringBuilder(200); + result.Append("<<\n"); + result.Append(" mode: "); + result.Append(mode); + result.Append("\n ecLevel: "); + result.Append(ecLevel); + result.Append("\n version: "); + result.Append(version); + result.Append("\n matrixWidth: "); + result.Append(matrixWidth); + result.Append("\n maskPattern: "); + result.Append(maskPattern); + result.Append("\n numTotalBytes: "); + result.Append(numTotalBytes); + result.Append("\n numDataBytes: "); + result.Append(numDataBytes); + result.Append("\n numECBytes: "); + result.Append(numECBytes); + result.Append("\n numRSBlocks: "); + result.Append(numRSBlocks); + if (matrix == null) { + result.Append("\n matrix: null\n"); + } + else { + result.Append("\n matrix:\n"); + result.Append(matrix.ToString()); + } + result.Append(">>\n"); + return result.ToString(); + } + + public void SetMode(Mode value) { + mode = value; + } + + public void SetECLevel(ErrorCorrectionLevel value) { + ecLevel = value; + } + + public void SetVersion(int value) { + version = value; + } + + public void SetMatrixWidth(int value) { + matrixWidth = value; + } + + public void SetMaskPattern(int value) { + maskPattern = value; + } + + public void SetNumTotalBytes(int value) { + numTotalBytes = value; + } + + public void SetNumDataBytes(int value) { + numDataBytes = value; + } + + public void SetNumECBytes(int value) { + numECBytes = value; + } + + public void SetNumRSBlocks(int value) { + numRSBlocks = value; + } + + // This takes ownership of the 2D array. + public void SetMatrix(ByteMatrix value) { + matrix = value; + } + + // Check if "mask_pattern" is valid. + public static bool IsValidMaskPattern(int maskPattern) { + return maskPattern >= 0 && maskPattern < NUM_MASK_PATTERNS; + } + + // Return true if the all values in the matrix are binary numbers. + // + // JAVAPORT: This is going to be super expensive and unnecessary, we should not call this in + // production. I'm leaving it because it may be useful for testing. It should be removed entirely + // if ByteMatrix is changed never to contain a -1. + /* + private static bool EverythingIsBinary(final ByteMatrix matrix) { + for (int y = 0; y < matrix.Height(); ++y) { + for (int x = 0; x < matrix.Width(); ++x) { + int value = matrix.Get(y, x); + if (!(value == 0 || value == 1)) { + // Found non zero/one value. + return false; + } + } + } + return true; + } + */ + } +} diff --git a/src/iTextSharp.LGPLv2.Core.FunctionalTests/QRCode.Apache.License/qrcode/QRCodeWriter.cs b/src/iTextSharp.LGPLv2.Core.FunctionalTests/QRCode.Apache.License/qrcode/QRCodeWriter.cs new file mode 100644 index 0000000..f4feb04 --- /dev/null +++ b/src/iTextSharp.LGPLv2.Core.FunctionalTests/QRCode.Apache.License/qrcode/QRCodeWriter.cs @@ -0,0 +1,134 @@ +using System; +using System.Collections.Generic; +using System.Text; +/* + * Copyright 2008 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +namespace iTextSharp.text.pdf.qrcode { + + /** + * This object renders a QR Code as a ByteMatrix 2D array of greyscale values. + * + * @author dswitkin@google.com (Daniel Switkin) + */ + public sealed class QRCodeWriter { + + private const int QUIET_ZONE_SIZE = 4; + + public ByteMatrix Encode(String contents, int width, int height) { + + return Encode(contents, width, height, null); + } + + public ByteMatrix Encode(String contents, int width, int height, + IDictionary hints) { + + if (contents == null || contents.Length == 0) { + throw new ArgumentException("Found empty contents"); + } + + if (width < 0 || height < 0) { + throw new ArgumentException("Requested dimensions are too small: " + width + 'x' + + height); + } + + ErrorCorrectionLevel errorCorrectionLevel = ErrorCorrectionLevel.L; + if (hints != null && hints.ContainsKey(EncodeHintType.ERROR_CORRECTION)) + errorCorrectionLevel = (ErrorCorrectionLevel)hints[EncodeHintType.ERROR_CORRECTION]; + + QRCode code = new QRCode(); + Encoder.Encode(contents, errorCorrectionLevel, hints, code); + return RenderResult(code, width, height); + } + + // Note that the input matrix uses 0 == white, 1 == black, while the output matrix uses + // 0 == black, 255 == white (i.e. an 8 bit greyscale bitmap). + private static ByteMatrix RenderResult(QRCode code, int width, int height) { + ByteMatrix input = code.GetMatrix(); + int inputWidth = input.GetWidth(); + int inputHeight = input.GetHeight(); + int qrWidth = inputWidth + (QUIET_ZONE_SIZE << 1); + int qrHeight = inputHeight + (QUIET_ZONE_SIZE << 1); + int outputWidth = Math.Max(width, qrWidth); + int outputHeight = Math.Max(height, qrHeight); + + int multiple = Math.Min(outputWidth / qrWidth, outputHeight / qrHeight); + // Padding includes both the quiet zone and the extra white pixels to accommodate the requested + // dimensions. For example, if input is 25x25 the QR will be 33x33 including the quiet zone. + // If the requested size is 200x160, the multiple will be 4, for a QR of 132x132. These will + // handle all the padding from 100x100 (the actual QR) up to 200x160. + int leftPadding = (outputWidth - (inputWidth * multiple)) / 2; + int topPadding = (outputHeight - (inputHeight * multiple)) / 2; + + ByteMatrix output = new ByteMatrix(outputWidth, outputHeight); + sbyte[][] outputArray = output.GetArray(); + + // We could be tricky and use the first row in each set of multiple as the temporary storage, + // instead of allocating this separate array. + sbyte[] row = new sbyte[outputWidth]; + + // 1. Write the white lines at the top + for (int y = 0; y < topPadding; y++) { + SetRowColor(outputArray[y], (sbyte)-1); + } + + // 2. Expand the QR image to the multiple + sbyte[][] inputArray = input.GetArray(); + for (int y = 0; y < inputHeight; y++) { + // a. Write the white pixels at the left of each row + for (int x = 0; x < leftPadding; x++) { + row[x] = (sbyte)-1; + } + + // b. Write the contents of this row of the barcode + int offset = leftPadding; + for (int x = 0; x < inputWidth; x++) { + sbyte value = (inputArray[y][x] == 1) ? (sbyte)0 : (sbyte)-1; + for (int z = 0; z < multiple; z++) { + row[offset + z] = value; + } + offset += multiple; + } + + // c. Write the white pixels at the right of each row + offset = leftPadding + (inputWidth * multiple); + for (int x = offset; x < outputWidth; x++) { + row[x] = (sbyte)-1; + } + + // d. Write the completed row multiple times + offset = topPadding + (y * multiple); + for (int z = 0; z < multiple; z++) { + System.Array.Copy(row, 0, outputArray[offset + z], 0, outputWidth); + } + } + + // 3. Write the white lines at the bottom + int offset2 = topPadding + (inputHeight * multiple); + for (int y = offset2; y < outputHeight; y++) { + SetRowColor(outputArray[y], (sbyte)-1); + } + + return output; + } + + private static void SetRowColor(sbyte[] row, sbyte value) { + for (int x = 0; x < row.Length; x++) { + row[x] = value; + } + } + } +} diff --git a/src/iTextSharp.LGPLv2.Core.FunctionalTests/QRCode.Apache.License/qrcode/ReedSolomonEncoder.cs b/src/iTextSharp.LGPLv2.Core.FunctionalTests/QRCode.Apache.License/qrcode/ReedSolomonEncoder.cs new file mode 100644 index 0000000..eba419c --- /dev/null +++ b/src/iTextSharp.LGPLv2.Core.FunctionalTests/QRCode.Apache.License/qrcode/ReedSolomonEncoder.cs @@ -0,0 +1,75 @@ +using System; +using System.Collections.Generic; +/* + * Copyright 2008 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +namespace iTextSharp.text.pdf.qrcode { + + /** + *

Implements Reed-Solomon enbcoding, as the name implies.

+ * + * @author Sean Owen + * @author William Rucklidge + */ + public sealed class ReedSolomonEncoder { + + private GF256 field; + private List cachedGenerators; + + public ReedSolomonEncoder(GF256 field) { + if (!GF256.QR_CODE_FIELD.Equals(field)) { + throw new ArgumentException("Only QR Code is supported at this time"); + } + this.field = field; + this.cachedGenerators = new List(); + cachedGenerators.Add(new GF256Poly(field, new int[] { 1 })); + } + + private GF256Poly BuildGenerator(int degree) { + if (degree >= cachedGenerators.Count) { + GF256Poly lastGenerator = cachedGenerators[cachedGenerators.Count - 1]; + for (int d = cachedGenerators.Count; d <= degree; d++) { + GF256Poly nextGenerator = lastGenerator.Multiply(new GF256Poly(field, new int[] { 1, field.Exp(d - 1) })); + cachedGenerators.Add(nextGenerator); + lastGenerator = nextGenerator; + } + } + return cachedGenerators[degree]; + } + + public void Encode(int[] toEncode, int ecBytes) { + if (ecBytes == 0) { + throw new ArgumentException("No error correction bytes"); + } + int dataBytes = toEncode.Length - ecBytes; + if (dataBytes <= 0) { + throw new ArgumentException("No data bytes provided"); + } + GF256Poly generator = BuildGenerator(ecBytes); + int[] infoCoefficients = new int[dataBytes]; + System.Array.Copy(toEncode, 0, infoCoefficients, 0, dataBytes); + GF256Poly info = new GF256Poly(field, infoCoefficients); + info = info.MultiplyByMonomial(ecBytes, 1); + GF256Poly remainder = info.Divide(generator)[1]; + int[] coefficients = remainder.GetCoefficients(); + int numZeroCoefficients = ecBytes - coefficients.Length; + for (int i = 0; i < numZeroCoefficients; i++) { + toEncode[dataBytes + i] = 0; + } + System.Array.Copy(coefficients, 0, toEncode, dataBytes + numZeroCoefficients, coefficients.Length); + } + } +} diff --git a/src/iTextSharp.LGPLv2.Core.FunctionalTests/QRCode.Apache.License/qrcode/ReedSolomonException.cs b/src/iTextSharp.LGPLv2.Core.FunctionalTests/QRCode.Apache.License/qrcode/ReedSolomonException.cs new file mode 100644 index 0000000..f3ecea7 --- /dev/null +++ b/src/iTextSharp.LGPLv2.Core.FunctionalTests/QRCode.Apache.License/qrcode/ReedSolomonException.cs @@ -0,0 +1,35 @@ +using System; +/* + * Copyright 2007 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +namespace iTextSharp.text.pdf.qrcode { + + /** + *

Thrown when an exception occurs during Reed-Solomon decoding, such as when + * there are too many errors to correct.

+ * + * @author Sean Owen + */ + [Serializable] + public sealed class ReedSolomonException : Exception { + + public ReedSolomonException(String message) + : base(message) { + } + + protected ReedSolomonException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) : base(info, context) { } + } +} diff --git a/src/iTextSharp.LGPLv2.Core.FunctionalTests/QRCode.Apache.License/qrcode/Version.cs b/src/iTextSharp.LGPLv2.Core.FunctionalTests/QRCode.Apache.License/qrcode/Version.cs new file mode 100644 index 0000000..fd75fa5 --- /dev/null +++ b/src/iTextSharp.LGPLv2.Core.FunctionalTests/QRCode.Apache.License/qrcode/Version.cs @@ -0,0 +1,585 @@ +using System; +/* + * Copyright 2007 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +namespace iTextSharp.text.pdf.qrcode { + + /** + * See ISO 18004:2006 Annex D + * + * @author Sean Owen + */ + public sealed class Version { + + /** + * See ISO 18004:2006 Annex D. + * Element i represents the raw version bits that specify version i + 7 + */ + private static readonly int[] VERSION_DECODE_INFO = { + 0x07C94, 0x085BC, 0x09A99, 0x0A4D3, 0x0BBF6, + 0x0C762, 0x0D847, 0x0E60D, 0x0F928, 0x10B78, + 0x1145D, 0x12A17, 0x13532, 0x149A6, 0x15683, + 0x168C9, 0x177EC, 0x18EC4, 0x191E1, 0x1AFAB, + 0x1B08E, 0x1CC1A, 0x1D33F, 0x1ED75, 0x1F250, + 0x209D5, 0x216F0, 0x228BA, 0x2379F, 0x24B0B, + 0x2542E, 0x26A64, 0x27541, 0x28C69 + }; + + private static readonly Version[] VERSIONS = BuildVersions(); + + private int versionNumber; + private int[] alignmentPatternCenters; + private ECBlocks[] ecBlocks; + private int totalCodewords; + + private Version(int versionNumber, + int[] alignmentPatternCenters, + ECBlocks ecBlocks1, + ECBlocks ecBlocks2, + ECBlocks ecBlocks3, + ECBlocks ecBlocks4) { + this.versionNumber = versionNumber; + this.alignmentPatternCenters = alignmentPatternCenters; + this.ecBlocks = new ECBlocks[] { ecBlocks1, ecBlocks2, ecBlocks3, ecBlocks4 }; + int total = 0; + int ecCodewords = ecBlocks1.GetECCodewordsPerBlock(); + ECB[] ecbArray = ecBlocks1.GetECBlocks(); + for (int i = 0; i < ecbArray.Length; i++) { + ECB ecBlock = ecbArray[i]; + total += ecBlock.GetCount() * (ecBlock.GetDataCodewords() + ecCodewords); + } + this.totalCodewords = total; + } + + public int GetVersionNumber() { + return versionNumber; + } + + public int[] GetAlignmentPatternCenters() { + return alignmentPatternCenters; + } + + public int GetTotalCodewords() { + return totalCodewords; + } + + public int GetDimensionForVersion() { + return 17 + 4 * versionNumber; + } + + public ECBlocks GetECBlocksForLevel(ErrorCorrectionLevel ecLevel) { + return ecBlocks[ecLevel.Ordinal()]; + } + + /** + *

Deduces version information purely from QR Code dimensions.

+ * + * @param dimension dimension in modules + * @return {@link Version} for a QR Code of that dimension + * @throws FormatException if dimension is not 1 mod 4 + */ + public static Version GetProvisionalVersionForDimension(int dimension) { + if (dimension % 4 != 1) { + throw new ArgumentException(); + } + try { + return GetVersionForNumber((dimension - 17) >> 2); + } + catch (ArgumentException iae) { + throw iae; + } + } + + public static Version GetVersionForNumber(int versionNumber) { + if (versionNumber < 1 || versionNumber > 40) { + throw new ArgumentException(); + } + return VERSIONS[versionNumber - 1]; + } + + static Version DecodeVersionInformation(int versionBits) { + int bestDifference = int.MaxValue; + int bestVersion = 0; + for (int i = 0; i < VERSION_DECODE_INFO.Length; i++) { + int targetVersion = VERSION_DECODE_INFO[i]; + // Do the version info bits match exactly? done. + if (targetVersion == versionBits) { + return GetVersionForNumber(i + 7); + } + // Otherwise see if this is the closest to a real version info bit string + // we have seen so far + int bitsDifference = FormatInformation.NumBitsDiffering(versionBits, targetVersion); + if (bitsDifference < bestDifference) { + bestVersion = i + 7; + bestDifference = bitsDifference; + } + } + // We can tolerate up to 3 bits of error since no two version info codewords will + // differ in less than 4 bits. + if (bestDifference <= 3) { + return GetVersionForNumber(bestVersion); + } + // If we didn't find a close enough match, fail + return null; + } + + /** + * See ISO 18004:2006 Annex E + */ + BitMatrix BuildFunctionPattern() { + int dimension = GetDimensionForVersion(); + BitMatrix bitMatrix = new BitMatrix(dimension); + + // Top left finder pattern + separator + format + bitMatrix.SetRegion(0, 0, 9, 9); + // Top right finder pattern + separator + format + bitMatrix.SetRegion(dimension - 8, 0, 8, 9); + // Bottom left finder pattern + separator + format + bitMatrix.SetRegion(0, dimension - 8, 9, 8); + + // Alignment patterns + int max = alignmentPatternCenters.Length; + for (int x = 0; x < max; x++) { + int i = alignmentPatternCenters[x] - 2; + for (int y = 0; y < max; y++) { + if ((x == 0 && (y == 0 || y == max - 1)) || (x == max - 1 && y == 0)) { + // No alignment patterns near the three finder paterns + continue; + } + bitMatrix.SetRegion(alignmentPatternCenters[y] - 2, i, 5, 5); + } + } + + // Vertical timing pattern + bitMatrix.SetRegion(6, 9, 1, dimension - 17); + // Horizontal timing pattern + bitMatrix.SetRegion(9, 6, dimension - 17, 1); + + if (versionNumber > 6) { + // Version info, top right + bitMatrix.SetRegion(dimension - 11, 0, 3, 6); + // Version info, bottom left + bitMatrix.SetRegion(0, dimension - 11, 6, 3); + } + + return bitMatrix; + } + + /** + *

Encapsulates a set of error-correction blocks in one symbol version. Most versions will + * use blocks of differing sizes within one version, so, this encapsulates the parameters for + * each set of blocks. It also holds the number of error-correction codewords per block since it + * will be the same across all blocks within one version.

+ */ + public sealed class ECBlocks { + private int ecCodewordsPerBlock; + private ECB[] ecBlocks; + + public ECBlocks(int ecCodewordsPerBlock, ECB ecBlocks) { + this.ecCodewordsPerBlock = ecCodewordsPerBlock; + this.ecBlocks = new ECB[] { ecBlocks }; + } + + public ECBlocks(int ecCodewordsPerBlock, ECB ecBlocks1, ECB ecBlocks2) { + this.ecCodewordsPerBlock = ecCodewordsPerBlock; + this.ecBlocks = new ECB[] { ecBlocks1, ecBlocks2 }; + } + + public int GetECCodewordsPerBlock() { + return ecCodewordsPerBlock; + } + + public int GetNumBlocks() { + int total = 0; + for (int i = 0; i < ecBlocks.Length; i++) { + total += ecBlocks[i].GetCount(); + } + return total; + } + + public int GetTotalECCodewords() { + return ecCodewordsPerBlock * GetNumBlocks(); + } + + public ECB[] GetECBlocks() { + return ecBlocks; + } + } + + /** + *

Encapsualtes the parameters for one error-correction block in one symbol version. + * This includes the number of data codewords, and the number of times a block with these + * parameters is used consecutively in the QR code version's format.

+ */ + public sealed class ECB { + private int count; + private int dataCodewords; + + public ECB(int count, int dataCodewords) { + this.count = count; + this.dataCodewords = dataCodewords; + } + + public int GetCount() { + return count; + } + + public int GetDataCodewords() { + return dataCodewords; + } + } + + public override String ToString() { + return versionNumber.ToString(); + } + + /** + * See ISO 18004:2006 6.5.1 Table 9 + */ + private static Version[] BuildVersions() { + return new Version[]{ + new Version(1, new int[]{}, + new ECBlocks(7, new ECB(1, 19)), + new ECBlocks(10, new ECB(1, 16)), + new ECBlocks(13, new ECB(1, 13)), + new ECBlocks(17, new ECB(1, 9))), + new Version(2, new int[]{6, 18}, + new ECBlocks(10, new ECB(1, 34)), + new ECBlocks(16, new ECB(1, 28)), + new ECBlocks(22, new ECB(1, 22)), + new ECBlocks(28, new ECB(1, 16))), + new Version(3, new int[]{6, 22}, + new ECBlocks(15, new ECB(1, 55)), + new ECBlocks(26, new ECB(1, 44)), + new ECBlocks(18, new ECB(2, 17)), + new ECBlocks(22, new ECB(2, 13))), + new Version(4, new int[]{6, 26}, + new ECBlocks(20, new ECB(1, 80)), + new ECBlocks(18, new ECB(2, 32)), + new ECBlocks(26, new ECB(2, 24)), + new ECBlocks(16, new ECB(4, 9))), + new Version(5, new int[]{6, 30}, + new ECBlocks(26, new ECB(1, 108)), + new ECBlocks(24, new ECB(2, 43)), + new ECBlocks(18, new ECB(2, 15), + new ECB(2, 16)), + new ECBlocks(22, new ECB(2, 11), + new ECB(2, 12))), + new Version(6, new int[]{6, 34}, + new ECBlocks(18, new ECB(2, 68)), + new ECBlocks(16, new ECB(4, 27)), + new ECBlocks(24, new ECB(4, 19)), + new ECBlocks(28, new ECB(4, 15))), + new Version(7, new int[]{6, 22, 38}, + new ECBlocks(20, new ECB(2, 78)), + new ECBlocks(18, new ECB(4, 31)), + new ECBlocks(18, new ECB(2, 14), + new ECB(4, 15)), + new ECBlocks(26, new ECB(4, 13), + new ECB(1, 14))), + new Version(8, new int[]{6, 24, 42}, + new ECBlocks(24, new ECB(2, 97)), + new ECBlocks(22, new ECB(2, 38), + new ECB(2, 39)), + new ECBlocks(22, new ECB(4, 18), + new ECB(2, 19)), + new ECBlocks(26, new ECB(4, 14), + new ECB(2, 15))), + new Version(9, new int[]{6, 26, 46}, + new ECBlocks(30, new ECB(2, 116)), + new ECBlocks(22, new ECB(3, 36), + new ECB(2, 37)), + new ECBlocks(20, new ECB(4, 16), + new ECB(4, 17)), + new ECBlocks(24, new ECB(4, 12), + new ECB(4, 13))), + new Version(10, new int[]{6, 28, 50}, + new ECBlocks(18, new ECB(2, 68), + new ECB(2, 69)), + new ECBlocks(26, new ECB(4, 43), + new ECB(1, 44)), + new ECBlocks(24, new ECB(6, 19), + new ECB(2, 20)), + new ECBlocks(28, new ECB(6, 15), + new ECB(2, 16))), + new Version(11, new int[]{6, 30, 54}, + new ECBlocks(20, new ECB(4, 81)), + new ECBlocks(30, new ECB(1, 50), + new ECB(4, 51)), + new ECBlocks(28, new ECB(4, 22), + new ECB(4, 23)), + new ECBlocks(24, new ECB(3, 12), + new ECB(8, 13))), + new Version(12, new int[]{6, 32, 58}, + new ECBlocks(24, new ECB(2, 92), + new ECB(2, 93)), + new ECBlocks(22, new ECB(6, 36), + new ECB(2, 37)), + new ECBlocks(26, new ECB(4, 20), + new ECB(6, 21)), + new ECBlocks(28, new ECB(7, 14), + new ECB(4, 15))), + new Version(13, new int[]{6, 34, 62}, + new ECBlocks(26, new ECB(4, 107)), + new ECBlocks(22, new ECB(8, 37), + new ECB(1, 38)), + new ECBlocks(24, new ECB(8, 20), + new ECB(4, 21)), + new ECBlocks(22, new ECB(12, 11), + new ECB(4, 12))), + new Version(14, new int[]{6, 26, 46, 66}, + new ECBlocks(30, new ECB(3, 115), + new ECB(1, 116)), + new ECBlocks(24, new ECB(4, 40), + new ECB(5, 41)), + new ECBlocks(20, new ECB(11, 16), + new ECB(5, 17)), + new ECBlocks(24, new ECB(11, 12), + new ECB(5, 13))), + new Version(15, new int[]{6, 26, 48, 70}, + new ECBlocks(22, new ECB(5, 87), + new ECB(1, 88)), + new ECBlocks(24, new ECB(5, 41), + new ECB(5, 42)), + new ECBlocks(30, new ECB(5, 24), + new ECB(7, 25)), + new ECBlocks(24, new ECB(11, 12), + new ECB(7, 13))), + new Version(16, new int[]{6, 26, 50, 74}, + new ECBlocks(24, new ECB(5, 98), + new ECB(1, 99)), + new ECBlocks(28, new ECB(7, 45), + new ECB(3, 46)), + new ECBlocks(24, new ECB(15, 19), + new ECB(2, 20)), + new ECBlocks(30, new ECB(3, 15), + new ECB(13, 16))), + new Version(17, new int[]{6, 30, 54, 78}, + new ECBlocks(28, new ECB(1, 107), + new ECB(5, 108)), + new ECBlocks(28, new ECB(10, 46), + new ECB(1, 47)), + new ECBlocks(28, new ECB(1, 22), + new ECB(15, 23)), + new ECBlocks(28, new ECB(2, 14), + new ECB(17, 15))), + new Version(18, new int[]{6, 30, 56, 82}, + new ECBlocks(30, new ECB(5, 120), + new ECB(1, 121)), + new ECBlocks(26, new ECB(9, 43), + new ECB(4, 44)), + new ECBlocks(28, new ECB(17, 22), + new ECB(1, 23)), + new ECBlocks(28, new ECB(2, 14), + new ECB(19, 15))), + new Version(19, new int[]{6, 30, 58, 86}, + new ECBlocks(28, new ECB(3, 113), + new ECB(4, 114)), + new ECBlocks(26, new ECB(3, 44), + new ECB(11, 45)), + new ECBlocks(26, new ECB(17, 21), + new ECB(4, 22)), + new ECBlocks(26, new ECB(9, 13), + new ECB(16, 14))), + new Version(20, new int[]{6, 34, 62, 90}, + new ECBlocks(28, new ECB(3, 107), + new ECB(5, 108)), + new ECBlocks(26, new ECB(3, 41), + new ECB(13, 42)), + new ECBlocks(30, new ECB(15, 24), + new ECB(5, 25)), + new ECBlocks(28, new ECB(15, 15), + new ECB(10, 16))), + new Version(21, new int[]{6, 28, 50, 72, 94}, + new ECBlocks(28, new ECB(4, 116), + new ECB(4, 117)), + new ECBlocks(26, new ECB(17, 42)), + new ECBlocks(28, new ECB(17, 22), + new ECB(6, 23)), + new ECBlocks(30, new ECB(19, 16), + new ECB(6, 17))), + new Version(22, new int[]{6, 26, 50, 74, 98}, + new ECBlocks(28, new ECB(2, 111), + new ECB(7, 112)), + new ECBlocks(28, new ECB(17, 46)), + new ECBlocks(30, new ECB(7, 24), + new ECB(16, 25)), + new ECBlocks(24, new ECB(34, 13))), + new Version(23, new int[]{6, 30, 54, 74, 102}, + new ECBlocks(30, new ECB(4, 121), + new ECB(5, 122)), + new ECBlocks(28, new ECB(4, 47), + new ECB(14, 48)), + new ECBlocks(30, new ECB(11, 24), + new ECB(14, 25)), + new ECBlocks(30, new ECB(16, 15), + new ECB(14, 16))), + new Version(24, new int[]{6, 28, 54, 80, 106}, + new ECBlocks(30, new ECB(6, 117), + new ECB(4, 118)), + new ECBlocks(28, new ECB(6, 45), + new ECB(14, 46)), + new ECBlocks(30, new ECB(11, 24), + new ECB(16, 25)), + new ECBlocks(30, new ECB(30, 16), + new ECB(2, 17))), + new Version(25, new int[]{6, 32, 58, 84, 110}, + new ECBlocks(26, new ECB(8, 106), + new ECB(4, 107)), + new ECBlocks(28, new ECB(8, 47), + new ECB(13, 48)), + new ECBlocks(30, new ECB(7, 24), + new ECB(22, 25)), + new ECBlocks(30, new ECB(22, 15), + new ECB(13, 16))), + new Version(26, new int[]{6, 30, 58, 86, 114}, + new ECBlocks(28, new ECB(10, 114), + new ECB(2, 115)), + new ECBlocks(28, new ECB(19, 46), + new ECB(4, 47)), + new ECBlocks(28, new ECB(28, 22), + new ECB(6, 23)), + new ECBlocks(30, new ECB(33, 16), + new ECB(4, 17))), + new Version(27, new int[]{6, 34, 62, 90, 118}, + new ECBlocks(30, new ECB(8, 122), + new ECB(4, 123)), + new ECBlocks(28, new ECB(22, 45), + new ECB(3, 46)), + new ECBlocks(30, new ECB(8, 23), + new ECB(26, 24)), + new ECBlocks(30, new ECB(12, 15), + new ECB(28, 16))), + new Version(28, new int[]{6, 26, 50, 74, 98, 122}, + new ECBlocks(30, new ECB(3, 117), + new ECB(10, 118)), + new ECBlocks(28, new ECB(3, 45), + new ECB(23, 46)), + new ECBlocks(30, new ECB(4, 24), + new ECB(31, 25)), + new ECBlocks(30, new ECB(11, 15), + new ECB(31, 16))), + new Version(29, new int[]{6, 30, 54, 78, 102, 126}, + new ECBlocks(30, new ECB(7, 116), + new ECB(7, 117)), + new ECBlocks(28, new ECB(21, 45), + new ECB(7, 46)), + new ECBlocks(30, new ECB(1, 23), + new ECB(37, 24)), + new ECBlocks(30, new ECB(19, 15), + new ECB(26, 16))), + new Version(30, new int[]{6, 26, 52, 78, 104, 130}, + new ECBlocks(30, new ECB(5, 115), + new ECB(10, 116)), + new ECBlocks(28, new ECB(19, 47), + new ECB(10, 48)), + new ECBlocks(30, new ECB(15, 24), + new ECB(25, 25)), + new ECBlocks(30, new ECB(23, 15), + new ECB(25, 16))), + new Version(31, new int[]{6, 30, 56, 82, 108, 134}, + new ECBlocks(30, new ECB(13, 115), + new ECB(3, 116)), + new ECBlocks(28, new ECB(2, 46), + new ECB(29, 47)), + new ECBlocks(30, new ECB(42, 24), + new ECB(1, 25)), + new ECBlocks(30, new ECB(23, 15), + new ECB(28, 16))), + new Version(32, new int[]{6, 34, 60, 86, 112, 138}, + new ECBlocks(30, new ECB(17, 115)), + new ECBlocks(28, new ECB(10, 46), + new ECB(23, 47)), + new ECBlocks(30, new ECB(10, 24), + new ECB(35, 25)), + new ECBlocks(30, new ECB(19, 15), + new ECB(35, 16))), + new Version(33, new int[]{6, 30, 58, 86, 114, 142}, + new ECBlocks(30, new ECB(17, 115), + new ECB(1, 116)), + new ECBlocks(28, new ECB(14, 46), + new ECB(21, 47)), + new ECBlocks(30, new ECB(29, 24), + new ECB(19, 25)), + new ECBlocks(30, new ECB(11, 15), + new ECB(46, 16))), + new Version(34, new int[]{6, 34, 62, 90, 118, 146}, + new ECBlocks(30, new ECB(13, 115), + new ECB(6, 116)), + new ECBlocks(28, new ECB(14, 46), + new ECB(23, 47)), + new ECBlocks(30, new ECB(44, 24), + new ECB(7, 25)), + new ECBlocks(30, new ECB(59, 16), + new ECB(1, 17))), + new Version(35, new int[]{6, 30, 54, 78, 102, 126, 150}, + new ECBlocks(30, new ECB(12, 121), + new ECB(7, 122)), + new ECBlocks(28, new ECB(12, 47), + new ECB(26, 48)), + new ECBlocks(30, new ECB(39, 24), + new ECB(14, 25)), + new ECBlocks(30, new ECB(22, 15), + new ECB(41, 16))), + new Version(36, new int[]{6, 24, 50, 76, 102, 128, 154}, + new ECBlocks(30, new ECB(6, 121), + new ECB(14, 122)), + new ECBlocks(28, new ECB(6, 47), + new ECB(34, 48)), + new ECBlocks(30, new ECB(46, 24), + new ECB(10, 25)), + new ECBlocks(30, new ECB(2, 15), + new ECB(64, 16))), + new Version(37, new int[]{6, 28, 54, 80, 106, 132, 158}, + new ECBlocks(30, new ECB(17, 122), + new ECB(4, 123)), + new ECBlocks(28, new ECB(29, 46), + new ECB(14, 47)), + new ECBlocks(30, new ECB(49, 24), + new ECB(10, 25)), + new ECBlocks(30, new ECB(24, 15), + new ECB(46, 16))), + new Version(38, new int[]{6, 32, 58, 84, 110, 136, 162}, + new ECBlocks(30, new ECB(4, 122), + new ECB(18, 123)), + new ECBlocks(28, new ECB(13, 46), + new ECB(32, 47)), + new ECBlocks(30, new ECB(48, 24), + new ECB(14, 25)), + new ECBlocks(30, new ECB(42, 15), + new ECB(32, 16))), + new Version(39, new int[]{6, 26, 54, 82, 110, 138, 166}, + new ECBlocks(30, new ECB(20, 117), + new ECB(4, 118)), + new ECBlocks(28, new ECB(40, 47), + new ECB(7, 48)), + new ECBlocks(30, new ECB(43, 24), + new ECB(22, 25)), + new ECBlocks(30, new ECB(10, 15), + new ECB(67, 16))), + new Version(40, new int[]{6, 30, 58, 86, 114, 142, 170}, + new ECBlocks(30, new ECB(19, 118), + new ECB(6, 119)), + new ECBlocks(28, new ECB(18, 47), + new ECB(31, 48)), + new ECBlocks(30, new ECB(34, 24), + new ECB(34, 25)), + new ECBlocks(30, new ECB(20, 15), + new ECB(61, 16))) + }; + } + } +} diff --git a/src/iTextSharp.LGPLv2.Core.FunctionalTests/QRCode.Apache.License/qrcode/WriterException.cs b/src/iTextSharp.LGPLv2.Core.FunctionalTests/QRCode.Apache.License/qrcode/WriterException.cs new file mode 100644 index 0000000..c7347bf --- /dev/null +++ b/src/iTextSharp.LGPLv2.Core.FunctionalTests/QRCode.Apache.License/qrcode/WriterException.cs @@ -0,0 +1,39 @@ +using System; +/* + * Copyright 2008 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +namespace iTextSharp.text.pdf.qrcode { + + /** + * A base class which covers the range of exceptions which may occur when encoding a barcode using + * the Writer framework. + * + * @author dswitkin@google.com (Daniel Switkin) + */ + [Serializable] + public sealed class WriterException : Exception { + + public WriterException() + : base() { + } + + public WriterException(String message) + : base(message) { + } + + protected WriterException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) : base(info, context) { } + } +}