iText и iTextSharp, очевидно, изначально не поддерживают это, но вы можете написать некоторый код, чтобы справиться с этим самостоятельно.Хитрость заключается в том, чтобы заставить синтаксический анализатор QR-кода работать только с произвольным байтовым массивом вместо строки.Что действительно приятно, так это то, что код iTextSharp почти готов к этому, но не раскрывает функциональность.К сожалению, многие из обязательных классов sealed
, поэтому вы не можете просто создать их подклассы, вам придется их воссоздать.Вы можете загрузить весь исходный код и добавить эти изменения или просто создать отдельные классы с одинаковыми именами.(Пожалуйста, проверьте лицензию, чтобы убедиться, что вам разрешено это делать.) Мои изменения ниже не содержат исправлений ошибок, поэтому убедитесь, что вы тоже это делаете.
Первый класс, который вам понадобитсявоссоздать это iTextSharp.text.pdf.qrcode.BlockPair
, и единственное изменение, которое вам нужно сделать, это сделать конструктор public
вместо internal
.(Это необходимо сделать только в том случае, если вы создаете свой собственный код и не изменяете существующий код.)
Второй класс - iTextSharp.text.pdf.qrcode.Encoder
.Здесь мы сделаем большинство изменений.Добавьте к Append8BitBytes
перегрузку, которая выглядит следующим образом:
static void Append8BitBytes(byte[] bytes, BitVector bits) {
for (int i = 0; i < bytes.Length; ++i) {
bits.AppendBits(bytes[i], 8);
}
}
Строковая версия этого метода преобразует текст в байтовый массив, а затем использует вышеприведенное, поэтому мы просто вырезали промежуточного человека.Затем добавьте новую перегрузку в конструктор, который принимает байтовый массив вместо строки.Затем мы просто отключим часть обнаружения строк и переведем систему в байтовый режим, в противном случае приведенный ниже код будет практически таким же.
public static void Encode(byte[] bytes, ErrorCorrectionLevel ecLevel, IDictionary<EncodeHintType, Object> hints, QRCode qrCode) {
String encoding = DEFAULT_BYTE_MODE_ENCODING;
// Step 1: Choose the mode (encoding).
Mode mode = Mode.BYTE;
// Step 2: Append "bytes" into "dataBits" in appropriate encoding.
BitVector dataBits = new BitVector();
Append8BitBytes(bytes, dataBits);
// 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 = dataBits.SizeInBytes();
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());
}
}
Третий класс - iTextSharp.text.pdf.qrcode.QRCodeWriter
и еще раз нам просто нужно добавить перегруженный Encode
метод, поддерживающий байтовый массив, и вызовы являются новым конструктором, созданным выше:
public ByteMatrix Encode(byte[] bytes, int width, int height, IDictionary<EncodeHintType, Object> hints) {
ErrorCorrectionLevel errorCorrectionLevel = ErrorCorrectionLevel.L;
if (hints != null && hints.ContainsKey(EncodeHintType.ERROR_CORRECTION))
errorCorrectionLevel = (ErrorCorrectionLevel)hints[EncodeHintType.ERROR_CORRECTION];
QRCode code = new QRCode();
Encoder.Encode(bytes, errorCorrectionLevel, hints, code);
return RenderResult(code, width, height);
}
Последний класс iTextSharp.text.pdf.BarcodeQRCode
к которому мы снова добавляем нашу новую конструкторскую перегрузку:
public BarcodeQRCode(byte[] bytes, int width, int height, IDictionary<EncodeHintType, Object> hints) {
newCode.QRCodeWriter qc = new newCode.QRCodeWriter();
bm = qc.Encode(bytes, width, height, hints);
}
Последний трюк заключается в том, чтобы при вызове этой функции убедиться, что вы добавили метку порядка байтов (BOM), чтобы декодеры знали, как правильно ее декодировать, вэто дело UTF-8.
//Create an encoder that supports outputting a BOM
System.Text.Encoding enc = new System.Text.UTF8Encoding(true, true);
//Get the BOM
byte[] bom = enc.GetPreamble();
//Get the raw bytes for the string
byte[] bytes = enc.GetBytes("测");
//Combine the byte arrays
byte[] final = new byte[bom.Length + bytes.Length];
System.Buffer.BlockCopy(bom, 0, final, 0, bom.Length);
System.Buffer.BlockCopy(bytes, 0, final, bom.Length, bytes.Length);
//Create are barcode using our new constructor
var q = new BarcodeQRCode(final, 100, 100, null);
//Add it to the document
doc.Add(q.GetImage());