public void test() { var qrCode = new QRCode(); // First, test simple setters and getters. // We use numbers of version 7-H. qrCode.Mode = Mode.BYTE; qrCode.ECLevel = ErrorCorrectionLevel.H; qrCode.Version = Version.getVersionForNumber(7); qrCode.MaskPattern = 3; Assert.AreEqual(Mode.BYTE, qrCode.Mode); Assert.AreEqual(ErrorCorrectionLevel.H, qrCode.ECLevel); Assert.AreEqual(7, qrCode.Version.VersionNumber); Assert.AreEqual(3, qrCode.MaskPattern); // Prepare the matrix. var matrix = new ByteMatrix(45, 45); // Just set bogus zero/one values. for (int y = 0; y < 45; ++y) { for (int x = 0; x < 45; ++x) { matrix.set(x, y, (y + x) % 2 == 1); } } // Set the matrix. qrCode.Matrix = matrix; Assert.AreEqual(matrix, qrCode.Matrix); }
// 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) { return MaskUtil.applyMaskPenaltyRule1(matrix) + MaskUtil.applyMaskPenaltyRule2(matrix) + MaskUtil.applyMaskPenaltyRule3(matrix) + MaskUtil.applyMaskPenaltyRule4(matrix); }
public void testApplyMaskPenaltyRule2() { var matrix = new ByteMatrix(1, 1); matrix.set(0, 0, 0); Assert.AreEqual(0, MaskUtil.applyMaskPenaltyRule2(matrix)); matrix = new ByteMatrix(2, 2); matrix.set(0, 0, 0); matrix.set(1, 0, 0); matrix.set(0, 1, 0); matrix.set(1, 1, 1); Assert.AreEqual(0, MaskUtil.applyMaskPenaltyRule2(matrix)); matrix = new ByteMatrix(2, 2); matrix.set(0, 0, 0); matrix.set(1, 0, 0); matrix.set(0, 1, 0); matrix.set(1, 1, 0); Assert.AreEqual(3, MaskUtil.applyMaskPenaltyRule2(matrix)); matrix = new ByteMatrix(3, 3); matrix.set(0, 0, 0); matrix.set(1, 0, 0); matrix.set(2, 0, 0); matrix.set(0, 1, 0); matrix.set(1, 1, 0); matrix.set(2, 1, 0); matrix.set(0, 2, 0); matrix.set(1, 2, 0); matrix.set(2, 2, 0); // Four instances of 2x2 blocks. Assert.AreEqual(3*4, MaskUtil.applyMaskPenaltyRule2(matrix)); }
public void testApplyMaskPenaltyRule1() { { ByteMatrix matrix = new ByteMatrix(4, 1); matrix.set(0, 0, 0); matrix.set(1, 0, 0); matrix.set(2, 0, 0); matrix.set(3, 0, 0); Assert.AreEqual(0, MaskUtil.applyMaskPenaltyRule1(matrix)); } { // Horizontal. ByteMatrix matrix = new ByteMatrix(6, 1); matrix.set(0, 0, 0); matrix.set(1, 0, 0); matrix.set(2, 0, 0); matrix.set(3, 0, 0); matrix.set(4, 0, 0); matrix.set(5, 0, 1); Assert.AreEqual(3, MaskUtil.applyMaskPenaltyRule1(matrix)); matrix.set(5, 0, 0); Assert.AreEqual(4, MaskUtil.applyMaskPenaltyRule1(matrix)); } { // Vertical. ByteMatrix matrix = new ByteMatrix(1, 6); matrix.set(0, 0, 0); matrix.set(0, 1, 0); matrix.set(0, 2, 0); matrix.set(0, 3, 0); matrix.set(0, 4, 0); matrix.set(0, 5, 1); Assert.AreEqual(3, MaskUtil.applyMaskPenaltyRule1(matrix)); matrix.set(0, 5, 0); Assert.AreEqual(4, MaskUtil.applyMaskPenaltyRule1(matrix)); } }
// Build 2D matrix of QR Code from "dataBits" with "ecLevel", "version" and "getMaskPattern". On // success, store the result in "matrix" and return true. //JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: //ORIGINAL LINE: static void buildMatrix(com.google.zxing.common.BitArray dataBits, com.google.zxing.qrcode.decoder.ErrorCorrectionLevel ecLevel, com.google.zxing.qrcode.decoder.Version version, int maskPattern, ByteMatrix matrix) throws com.google.zxing.WriterException internal static void buildMatrix(BitArray dataBits, ErrorCorrectionLevel ecLevel, Version 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); }
public static BitMatrix Encode(string content, ErrorCorrectionLevel ecLevel) { QRCodeInternal qrInternal; BitVector headerAndDataBits = DataEncodeUsingReferenceImplementation(content, ecLevel, out qrInternal); // Step 6: Interleave data bits with error correction code. BitVector finalBits = new BitVector(); EncoderInternal.interleaveWithECBytes(headerAndDataBits, qrInternal.NumTotalBytes, qrInternal.NumDataBytes, qrInternal.NumRSBlocks, finalBits); // Step 7: Choose the mask pattern and set to "QRCodeInternal". ByteMatrix matrix = new ByteMatrix(qrInternal.MatrixWidth, qrInternal.MatrixWidth); int MaskPattern = EncoderInternal.chooseMaskPattern(finalBits, qrInternal.EcLevelInternal, qrInternal.Version, matrix); // Step 8. Build the matrix and set it to "QRCodeInternal". MatrixUtil.buildMatrix(finalBits, qrInternal.EcLevelInternal, qrInternal.Version, MaskPattern, matrix); return matrix.ToBitMatrix(); }
public void testBuildMatrix() { // From http://www.swetake.com/qr/qr7.html String expected = " 1 1 1 1 1 1 1 0 0 1 1 0 0 0 1 1 1 1 1 1 1\n" + " 1 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 1\n" + " 1 0 1 1 1 0 1 0 0 0 0 1 0 0 1 0 1 1 1 0 1\n" + " 1 0 1 1 1 0 1 0 0 1 1 0 0 0 1 0 1 1 1 0 1\n" + " 1 0 1 1 1 0 1 0 1 1 0 0 1 0 1 0 1 1 1 0 1\n" + " 1 0 0 0 0 0 1 0 0 0 1 1 1 0 1 0 0 0 0 0 1\n" + " 1 1 1 1 1 1 1 0 1 0 1 0 1 0 1 1 1 1 1 1 1\n" + " 0 0 0 0 0 0 0 0 1 1 0 1 1 0 0 0 0 0 0 0 0\n" + " 0 0 1 1 0 0 1 1 1 0 0 1 1 1 1 0 1 0 0 0 0\n" + " 1 0 1 0 1 0 0 0 0 0 1 1 1 0 0 1 0 1 1 1 0\n" + " 1 1 1 1 0 1 1 0 1 0 1 1 1 0 0 1 1 1 0 1 0\n" + " 1 0 1 0 1 1 0 1 1 1 0 0 1 1 1 0 0 1 0 1 0\n" + " 0 0 1 0 0 1 1 1 0 0 0 0 0 0 1 0 1 1 1 1 1\n" + " 0 0 0 0 0 0 0 0 1 1 0 1 0 0 0 0 0 1 0 1 1\n" + " 1 1 1 1 1 1 1 0 1 1 1 1 0 0 0 0 1 0 1 1 0\n" + " 1 0 0 0 0 0 1 0 0 0 0 1 0 1 1 1 0 0 0 0 0\n" + " 1 0 1 1 1 0 1 0 0 1 0 0 1 1 0 0 1 0 0 1 1\n" + " 1 0 1 1 1 0 1 0 1 1 0 1 0 0 0 0 0 1 1 1 0\n" + " 1 0 1 1 1 0 1 0 1 1 1 1 0 0 0 0 1 1 1 0 0\n" + " 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 1 0 0\n" + " 1 1 1 1 1 1 1 0 0 0 1 1 1 1 1 0 1 0 0 1 0\n"; int[] bytes = { 32, 65, 205, 69, 41, 220, 46, 128, 236, 42, 159, 74, 221, 244, 169, 239, 150, 138, 70, 237, 85, 224, 96, 74, 219, 61 }; BitArray bits = new BitArray(); foreach (char c in bytes) { bits.appendBits(c, 8); } ByteMatrix matrix = new ByteMatrix(21, 21); MatrixUtil.buildMatrix(bits, ErrorCorrectionLevel.H, Version.getVersionForNumber(1), // Version 1 3, // Mask pattern 3 matrix); Assert.AreEqual(expected, matrix.ToString()); }
private void GenQR(string ssconfig) { int dpi_mul = Util.Utils.GetDpiMul(); int width = 350 * dpi_mul / 4; if (txtLink.Focused) { string qrText = ssconfig; QRCode code = ZXing.QrCode.Internal.Encoder.encode(qrText, ErrorCorrectionLevel.M); ByteMatrix m = code.Matrix; int blockSize = Math.Max(width / (m.Width + 2), 1); Bitmap drawArea = new Bitmap(((m.Width + 2) * blockSize), ((m.Height + 2) * blockSize)); using (Graphics g = Graphics.FromImage(drawArea)) { g.Clear(Color.White); using (Brush b = new SolidBrush(Color.Black)) { for (int row = 0; row < m.Width; row++) { for (int col = 0; col < m.Height; col++) { if (m[row, col] != 0) { g.FillRectangle(b, blockSize * (row + 1), blockSize * (col + 1), blockSize, blockSize); } } } } Bitmap ngnl = Resources.ngnl; int div = 13, div_l = 5, div_r = 8; int l = (m.Width * div_l + div - 1) / div * blockSize, r = (m.Width * div_r + div - 1) / div * blockSize; g.DrawImage(ngnl, new Rectangle(l + blockSize, l + blockSize, r - l, r - l)); } picQRcode.Image = drawArea; picQRcode.Visible = true; _modifiedConfiguration.isHideTips = true; } else { //PictureQRcode.Visible = false; DrawLogo(picQRcode.Width); } }
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.Length != 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[yStart + y, xStart + x])) { throw new WriterException(); } matrix[yStart + y, xStart + x] = (sbyte)POSITION_DETECTION_PATTERN[y][x]; } } }
/// <summary> /// Apply mask penalty rule 2 and return the penalty. Find 2x2 blocks with the same color and give /// penalty to them. This is actually equivalent to the spec's rule, which is to find MxN blocks and give a /// penalty proportional to (M-1)x(N-1), because this is the number of 2x2 blocks inside such a block. /// </summary> internal static int applyMaskPenaltyRule2(ByteMatrix matrix) { int penalty = 0; sbyte[][] array = matrix.Array; int width = matrix.Width; int height = matrix.Height; 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++; } } } return N2 * penalty; }
//普通二维码 private void btnEncode_Click(object sender, EventArgs e) { labShow.Text = ""; string content = txtMsg.Text.Trim(); if (String.IsNullOrEmpty(content)) { MessageBox.Show("请输入原文!"); return; } try { MultiFormatWriter writer = new MultiFormatWriter(); ByteMatrix matrix = writer.encode(content, BarcodeFormat.QR_CODE, 300, 300); Bitmap img = matrix.ToBitmap(); //将img转换成bmp格式,否则后面无法创建 Graphics对象 Bitmap bmpimg = new Bitmap(img.Width, img.Height, PixelFormat.Format32bppArgb); using (Graphics g = Graphics.FromImage(bmpimg)) { g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic; g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality; g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality; g.DrawImage(img, 0, 0); } Graphics MyGraphic = Graphics.FromImage(bmpimg); float x = pictureBox1.Width / 2 - 50; float y = pictureBox1.Height - 30; MyGraphic.DrawString(content, this.Font, new SolidBrush(Color.Black), x, y); pictureBox1.Image = bmpimg; //自动保存图片到默认目录 //string filename = Environment.CurrentDirectory + "\\QR" + DateTime.Now.Ticks.ToString() + ".jpg"; //bitmap.Save(filename, System.Drawing.Imaging.ImageFormat.Jpeg); //labShow.Text = "图片已保存到:" + filename; } catch (Exception ex) { MessageBox.Show(ex.Message); } }
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.Width - 8; ++i) { int bit = (i + 1) % 2; // Horizontal line. if (isEmpty(matrix.get(i, 6))) { matrix.set(i, 6, bit); } // Vertical line. if (isEmpty(matrix.get(6, i))) { matrix.set(6, i, bit); } } }
// 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.Length != 5) { throw new WriterException("Bad position adjustment"); } for (int y = 0; y < 5; ++y) { for (int x = 0; x < 5; ++x) { if (!isEmpty(matrix[yStart + y, xStart + x])) { throw new WriterException(); } matrix[yStart + y, xStart + x] = (sbyte)POSITION_ADJUSTMENT_PATTERN[y][x]; } } }
/// <summary> /// 获取二维码位图 /// </summary> /// <param name="ngnl">原始logo</param> /// <param name="width">二维码显示多大,默认350,数字越大则图越大</param> /// <returns></returns> public Bitmap GetQR(int width = 350, Bitmap ngnl = null) { if (buff == null || buff == "") { return(null); } if (ngnl == null) { ngnl = new Bitmap(10, 10); } int dpi_mul = GetDpiMul(); width = width * dpi_mul / 4; string qrText = buff; QRCode code = ZXing.QrCode.Internal.Encoder.encode(qrText, ErrorCorrectionLevel.M); ByteMatrix m = code.Matrix; int blockSize = Math.Max(width / (m.Width + 2), 1); Bitmap drawArea = new Bitmap(((m.Width + 2) * blockSize), ((m.Height + 2) * blockSize)); using (Graphics g = Graphics.FromImage(drawArea)) { g.Clear(Color.White); using (Brush b = new SolidBrush(Color.Black)) { for (int row = 0; row < m.Width; row++) { for (int col = 0; col < m.Height; col++) { if (m[row, col] != 0) { g.FillRectangle(b, blockSize * (row + 1), blockSize * (col + 1), blockSize, blockSize); } } } } int div = 13, div_l = 5, div_r = 8; int l = (m.Width * div_l + div - 1) / div * blockSize, r = (m.Width * div_r + div - 1) / div * blockSize; g.DrawImage(ngnl, new Rectangle(l + blockSize, l + blockSize, r - l, r - l)); } return(drawArea); }
public static Bitmap Create(string content, Image centralImage) { //构造二维码写码器 MultiFormatWriter mutiWriter = new com.google.zxing.MultiFormatWriter(); Hashtable hint = new Hashtable(); hint.Add(EncodeHintType.CHARACTER_SET, "UTF-8"); hint.Add(EncodeHintType.ERROR_CORRECTION, com.google.zxing.qrcode.decoder.ErrorCorrectionLevel.H); //生成二维码 ByteMatrix bm = mutiWriter.encode(content, com.google.zxing.BarcodeFormat.QR_CODE, 300, 300, hint); Bitmap img = bm.ToBitmap(); //要插入到二维码中的图片 Image middlImg = centralImage; //获取二维码实际尺寸(去掉二维码两边空白后的实际尺寸) // System.Drawing.Size realSize = mutiWriter.GetEncodeSize(content, com.google.zxing.BarcodeFormat.QR_CODE, 300, 300); var realSize = mutiWriter.encode(content, com.google.zxing.BarcodeFormat.QR_CODE, 300, 300); //计算插入图片的大小和位置 int middleImgW = Math.Min((int)(realSize.Width / 3.5), middlImg.Width); int middleImgH = Math.Min((int)(realSize.Height / 3.5), middlImg.Height); int middleImgL = (img.Width - middleImgW) / 2; int middleImgT = (img.Height - middleImgH) / 2; //将img转换成bmp格式,否则后面无法创建 Graphics对象 Bitmap bmpimg = new Bitmap(img.Width, img.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb); using (Graphics g = Graphics.FromImage(bmpimg)) { g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic; g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality; g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality; g.DrawImage(img, 0, 0); } //在二维码中插入图片 System.Drawing.Graphics MyGraphic = System.Drawing.Graphics.FromImage(bmpimg); //白底 MyGraphic.FillRectangle(Brushes.White, middleImgL, middleImgT, middleImgW, middleImgH); MyGraphic.DrawImage(middlImg, middleImgL, middleImgT, middleImgW, middleImgH); return(bmpimg); }
private void button1_Click(object sender, EventArgs e) { try { MultiFormatWriter mutiWriter = new com.google.zxing.MultiFormatWriter(); //ByteMatrix bm = mutiWriter.encode(txtMsg.Text, com.google.zxing.BarcodeFormat.QR_CODE, 300, 300);//二维码 ByteMatrix bm = mutiWriter.encode(txtMsg.Text, com.google.zxing.BarcodeFormat.EAN_8, 300, 300);//8位数字 Bitmap img = bm.ToBitmap(); pictureBox1.Width = img.Width; pictureBox1.Height = img.Height; pictureBox1.Image = img; //自动保存图片到当前目录 string filename = System.Environment.CurrentDirectory + "\\QR" + DateTime.Now.Ticks.ToString() + ".jpg"; img.Save(filename, System.Drawing.Imaging.ImageFormat.Jpeg); lbshow.Text = "图片已保存到:" + filename; } catch (Exception ex) { MessageBox.Show(ex.Message); } }
// 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 (var y = 0; y < 5; ++y) { for (var 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 (var y = 0; y < 7; ++y) { for (var 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]); } } }
/// <summary> /// Convert the ByteMatrix to BitMatrix. /// </summary> /// <param name="matrix">The input matrix.</param> /// <param name="reqWidth">The requested width of the image (in pixels) with the Datamatrix code</param> /// <param name="reqHeight">The requested height of the image (in pixels) with the Datamatrix code</param> /// <returns>The output matrix.</returns> private static BitMatrix convertByteMatrixToBitMatrix(ByteMatrix matrix, int reqWidth, int reqHeight) { var matrixWidth = matrix.Width; var matrixHeight = matrix.Height; var outputWidth = Math.Max(reqWidth, matrixWidth); var outputHeight = Math.Max(reqHeight, matrixHeight); int multiple = Math.Min(outputWidth / matrixWidth, outputHeight / matrixHeight); int leftPadding = (outputWidth - (matrixWidth * multiple)) / 2; int topPadding = (outputHeight - (matrixHeight * multiple)) / 2; BitMatrix output; // remove padding if requested width and height are too small if (reqHeight < matrixHeight || reqWidth < matrixWidth) { leftPadding = 0; topPadding = 0; output = new BitMatrix(matrixWidth, matrixHeight); } else { output = new BitMatrix(reqWidth, reqHeight); } output.clear(); for (int inputY = 0, outputY = topPadding; inputY < matrixHeight; inputY++, outputY += multiple) { // Write the contents of this row of the bytematrix for (int inputX = 0, outputX = leftPadding; inputX < matrixWidth; inputX++, outputX += multiple) { if (matrix[inputX, inputY] == 1) { output.setRegion(outputX, outputY, multiple, multiple); } } } return(output); }
/// <summary> /// Apply mask penalty rule 2 and return the penalty. Find 2x2 blocks with the same color and give /// penalty to them. This is actually equivalent to the spec's rule, which is to find MxN blocks and give a /// penalty proportional to (M-1)x(N-1), because this is the number of 2x2 blocks inside such a block. /// </summary> internal static int applyMaskPenaltyRule2(ByteMatrix matrix) { int penalty = 0; sbyte[][] array = matrix.Array; int width = matrix.Width; int height = matrix.Height; 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++; } } } return(N2 * penalty); }
public static ByteMatrix CreateRawQR(byte[] rawData, ErrorCorrectionLevel errorCorrectionLevel) { int versionNumber = GetSmallestVersion(rawData.Length, errorCorrectionLevel); ZXing.QrCode.Internal.Version version = ZXing.QrCode.Internal.Version.getVersionForNumber(versionNumber); BitArray dataBits = new BitArray(); foreach (byte b in rawData) dataBits.appendBits(b, 8); ZXing.QrCode.Internal.Version.ECBlocks ecBlocks = version.getECBlocksForLevel(errorCorrectionLevel); int bytesLength = version.TotalCodewords - ecBlocks.TotalECCodewords; terminateBits(bytesLength, dataBits); BitArray resultBits = interleaveWithECBytes(dataBits, version.TotalCodewords, bytesLength, ecBlocks.NumBlocks); ByteMatrix matrix = new ByteMatrix(version.DimensionForVersion, version.DimensionForVersion); int maskPattern = chooseMaskPattern(resultBits, errorCorrectionLevel, version, matrix); MatrixUtil.buildMatrix(resultBits, errorCorrectionLevel, version, maskPattern, matrix); return matrix; }
// 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.width(); int height = matrix.height(); 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); }
private void GenQR(string ssconfig) { int dpi_mul = Util.Utils.GetDpiMul(); int width = Math.Min(PictureQRcode.Width, PictureQRcode.Height) * 4 / 4; try { string qrText = ssconfig; QRCode code = ZXing.QrCode.Internal.Encoder.encode(qrText, ErrorCorrectionLevel.M); ByteMatrix m = code.Matrix; int blockSize = Math.Max(width / (m.Width + 2), 1); Bitmap drawArea = new Bitmap(((m.Width + 2) * blockSize), ((m.Height + 2) * blockSize)); using (Graphics g = Graphics.FromImage(drawArea)) { g.Clear(Color.White); using (Brush b = new SolidBrush(Color.Black)) { for (int row = 0; row < m.Width; row++) { for (int col = 0; col < m.Height; col++) { if (m[row, col] != 0) { g.FillRectangle(b, blockSize * (row + 1), blockSize * (col + 1), blockSize, blockSize); } } } } Bitmap ngnl = Resources.ngnl; int div = 13, div_l = 5, div_r = 8; int l = (m.Width * div_l + div - 1) / div * blockSize, r = (m.Width * div_r + div - 1) / div * blockSize; g.DrawImage(ngnl, new Rectangle(l + blockSize, l + blockSize, r - l, r - l)); } PictureQRcode.Image = drawArea; } catch { } }
public void testApplyMaskPenaltyRule4() { // Dark cell ratio = 0% var matrix = new ByteMatrix(1, 1); matrix.set(0, 0, 0); Assert.AreEqual(100, MaskUtil.applyMaskPenaltyRule4(matrix)); // Dark cell ratio = 5% matrix = new ByteMatrix(2, 1); matrix.set(0, 0, 0); matrix.set(0, 0, 1); Assert.AreEqual(0, MaskUtil.applyMaskPenaltyRule4(matrix)); // Dark cell ratio = 66.67% matrix = new ByteMatrix(6, 1); matrix.set(0, 0, 0); matrix.set(1, 0, 1); matrix.set(2, 0, 1); matrix.set(3, 0, 1); matrix.set(4, 0, 1); matrix.set(5, 0, 0); Assert.AreEqual(30, MaskUtil.applyMaskPenaltyRule4(matrix)); }
// 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 internal static int applyMaskPenaltyRule4(ByteMatrix matrix) { int numDarkCells = 0; int width = matrix.Width; int height = matrix.Height; for (int y = 0; y < height; ++y) { for (int x = 0; x < width; ++x) { if (matrix[x, y] == 1) { numDarkCells += 1; } } } int numTotalCells = matrix.Height * matrix.Width; double darkRatio = (double)numDarkCells / numTotalCells; //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" return(System.Math.Abs((int)(darkRatio * 100 - 50)) / 5 * 10); }
// 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 BitMatrix renderResult(QRCode code, int width, int height, int quietZone) { ByteMatrix input = code.Matrix; if (input == null) { throw new InvalidOperationException(); } int inputWidth = input.Width; int inputHeight = input.Height; int qrWidth = inputWidth + (quietZone << 1); int qrHeight = inputHeight + (quietZone << 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; BitMatrix output = new BitMatrix(outputWidth, outputHeight); for (int inputY = 0, outputY = topPadding; inputY < inputHeight; inputY++, outputY += multiple) { // Write the contents of this row of the barcode for (int inputX = 0, outputX = leftPadding; inputX < inputWidth; inputX++, outputX += multiple) { if (input.get(inputX, inputY) == 1) { output.setRegion(outputX, outputY, multiple, multiple); } } } return(output); }
public static Bitmap Create(string content, Image centralImage) { MultiFormatWriter multiFormatWriter = new MultiFormatWriter(); Hashtable hashtables = new Hashtable() { { EncodeHintType.CHARACTER_SET, "UTF-8" }, { EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H } }; ByteMatrix byteMatrix = multiFormatWriter.encode(content, BarcodeFormat.QR_CODE, 300, 300, hashtables); Bitmap bitmap = byteMatrix.ToBitmap(); Image image = centralImage; Size encodeSize = multiFormatWriter.GetEncodeSize(content, BarcodeFormat.QR_CODE, 300, 300); int num = Math.Min((int)(encodeSize.Width / 3.5), image.Width); int num1 = Math.Min((int)(encodeSize.Height / 3.5), image.Height); int width = (bitmap.Width - num) / 2; int height = (bitmap.Height - num1) / 2; Bitmap bitmap1 = new Bitmap(bitmap.Width, bitmap.Height, PixelFormat.Format32bppArgb); Graphics graphic = Graphics.FromImage(bitmap1); try { graphic.InterpolationMode = InterpolationMode.HighQualityBicubic; graphic.SmoothingMode = SmoothingMode.HighQuality; graphic.CompositingQuality = CompositingQuality.HighQuality; graphic.DrawImage(bitmap, 0, 0); } finally { if (graphic != null) { graphic.Dispose(); } } Graphics graphic1 = Graphics.FromImage(bitmap1); graphic1.FillRectangle(Brushes.White, width, height, num, num1); graphic1.DrawImage(image, width, height, num, num1); return(bitmap1); }
/// <summary> /// Convert the ByteMatrix to BitMatrix. /// </summary> /// <param name="matrix">The input matrix.</param> /// <returns>The output matrix.</returns> private static BitMatrix convertByteMatrixToBitMatrix(ByteMatrix matrix) { int matrixWidgth = matrix.Width; int matrixHeight = matrix.Height; var output = new BitMatrix(matrixWidgth, matrixHeight); output.clear(); for (int i = 0; i < matrixWidgth; i++) { for (int j = 0; j < matrixHeight; j++) { // Zero is white in the bytematrix if (matrix[i, j] == 1) { output[i, j] = true; } } } return(output); }
public void testApplyMaskPenaltyRule2() { { ByteMatrix matrix = new ByteMatrix(1, 1); matrix.set(0, 0, 0); Assert.AreEqual(0, MaskUtil.applyMaskPenaltyRule2(matrix)); } { ByteMatrix matrix = new ByteMatrix(2, 2); matrix.set(0, 0, 0); matrix.set(1, 0, 0); matrix.set(0, 1, 0); matrix.set(1, 1, 1); Assert.AreEqual(0, MaskUtil.applyMaskPenaltyRule2(matrix)); } { ByteMatrix matrix = new ByteMatrix(2, 2); matrix.set(0, 0, 0); matrix.set(1, 0, 0); matrix.set(0, 1, 0); matrix.set(1, 1, 0); Assert.AreEqual(3, MaskUtil.applyMaskPenaltyRule2(matrix)); } { ByteMatrix matrix = new ByteMatrix(3, 3); matrix.set(0, 0, 0); matrix.set(1, 0, 0); matrix.set(2, 0, 0); matrix.set(0, 1, 0); matrix.set(1, 1, 0); matrix.set(2, 1, 0); matrix.set(0, 2, 0); matrix.set(1, 2, 0); matrix.set(2, 2, 0); // Four instances of 2x2 blocks. Assert.AreEqual(3 * 4, MaskUtil.applyMaskPenaltyRule2(matrix)); } }
private void btnBarCode_Click(object sender, EventArgs e) { labShow.Text = ""; string content = txtMsg.Text.Trim(); Regex regex = new Regex("^[0-9]{13}$"); if (!regex.IsMatch(content)) { MessageBox.Show("请输入13位的数字!"); return; } try { MultiFormatWriter writer = new MultiFormatWriter(); ByteMatrix matrix = writer.encode(content, BarcodeFormat.EAN_13, 360, 150); Bitmap bitmap = matrix.ToBitmap(); pictureBox1.Image = bitmap; //自动保存图片到当前目录 SaveFileDialog save = new SaveFileDialog(); save.Title = "保存文件"; save.Filter = "图片文件|*.jpg;*.png;*.bmp|所有文件|*.*"; save.RestoreDirectory = true; save.InitialDirectory = Application.StartupPath; if (save.ShowDialog() == DialogResult.OK) { string filename = save.FileName; bitmap.Save(filename); labShow.Text = "图片已保存到:" + filename; } } catch (Exception ex) { MessageBox.Show(ex.Message); } }
private void txtBarcodeInput_TextChanged(object sender, TextChangedEventArgs e) { if (this.txtBarcodeInput.Text.Length == 13 && barcodeControl != null) { MultiFormatWriter barcodeWriter = new MultiFormatWriter(); Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Send, new Action(delegate { _Global_C_ShowWaitingScreen(); ByteMatrix barcodeData = barcodeWriter.encode(txtBarcodeInput.Text, BarcodeFormat.EAN_13, (int)(barcodeControl.imgBarcodeImg.Width), (int)(barcodeControl.imgBarcodeImg.Height * 0.8)); barcodeControl.imgBarcodeImg.Source = getImageSource(barcodeData.ToBitmap()); })); _Barcode_D_Dispose(txtBarcodeInput.Text); } else if (this.txtBarcodeInput.Text.Length == 16 && membershipControl != null) { MultiFormatWriter barcodeWriter = new MultiFormatWriter(); Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Send, new Action(delegate { _Global_C_ShowWaitingScreen(); })); _Membership_D_Dispose(txtBarcodeInput.Text); } }
private unsafe Bitmap ConvertByteMatrixToImage(ByteMatrix bm) { Bitmap image = CreateGrayscaleImage(bm.Width, bm.Height); BitmapData sourceData; sourceData = image.LockBits(new Rectangle(0, 0, image.Width, image.Height), ImageLockMode.ReadOnly, image.PixelFormat); int width = sourceData.Width; int height = sourceData.Height; int srcOffset = sourceData.Stride - width; byte* src = (byte*)sourceData.Scan0.ToPointer(); for (int y = 0; y < height; y++) { // for each pixel for (int x = 0; x < width; x++, src++) { *src = (byte)bm.Array[y][x]; } src += srcOffset; } image.UnlockBits(sourceData); return image; }
// 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). internal static int applyMaskPenaltyRule3(ByteMatrix matrix) { int penalty = 0; int width = matrix.Width; int height = matrix.Height; 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 && matrix[x, y] == 1 && matrix[x + 1, y] == 0 && matrix[x + 2, y] == 1 && matrix[x + 3, y] == 1 && matrix[x + 4, y] == 1 && matrix[x + 5, y] == 0 && matrix[x + 6, y] == 1 && ((x + 10 < width && matrix[x + 7, y] == 0 && matrix[x + 8, y] == 0 && matrix[x + 9, y] == 0 && matrix[x + 10, y] == 0) || (x - 4 >= 0 && matrix[x - 1, y] == 0 && matrix[x - 2, y] == 0 && matrix[x - 3, y] == 0 && matrix[x - 4, y] == 0))) { penalty += 40; } if (y + 6 < height && matrix[x, y] == 1 && matrix[x, y + 1] == 0 && matrix[x, y + 2] == 1 && matrix[x, y + 3] == 1 && matrix[x, y + 4] == 1 && matrix[x, y + 5] == 0 && matrix[x, y + 6] == 1 && ((y + 10 < height && matrix[x, y + 7] == 0 && matrix[x, y + 8] == 0 && matrix[x, y + 9] == 0 && matrix[x, y + 10] == 0) || (y - 4 >= 0 && matrix[x, y - 1] == 0 && matrix[x, y - 2] == 0 && matrix[x, y - 3] == 0 && matrix[x, y - 4] == 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.width(); int height = matrix.height(); for (int y = 0; y < height; ++y) { for (int x = 0; x < width; ++x) { if (array[y][x] == 1) { numDarkCells += 1; } } } int numTotalCells = matrix.height() * matrix.width(); double darkRatio = (double)numDarkCells / numTotalCells; return(Math.Abs((int)(darkRatio * 100 - 50)) / 5 * 10); }
static void Main(string[] args) { var b = BarcodeFormat.QrCode; var g = Guid.NewGuid().ToString(); string t = "data=" + g; ByteMatrix bt = barcodeWriter.Encode(t, b, 150, 150); Image i = ConvertByteMatrixToImage(bt); i.Save(".\\" + g + ".png", ImageFormat.Png); Bitmap bitmap = new Bitmap(i); Result rawResult; RGBLuminanceSource r = new RGBLuminanceSource(bitmap, 150, 150); GlobalHistogramBinarizer x = new GlobalHistogramBinarizer(r); BinaryBitmap bitmap2 = new BinaryBitmap(x); var hints = new System.Collections.Hashtable(); //hints.Add(DecodeHintType.PossibleFormats, BarcodeFormat.QrCode); int count = 0; { try { rawResult = barcodeReader.Decode(bitmap2, hints); if (rawResult != null) { count++; var y = rawResult.Text; var z = rawResult.BarcodeFormat.ToString(); } } catch (ReaderException e) { return; } } }
public Sprite CreateQRCode(string context, Texture2D gameLogo = null, int offsetX = 0, int offsetY = 0) { QRCodeWriter qrwriter = new QRCodeWriter(); Hashtable table = new Hashtable(); table[EncodeHintType.ERROR_CORRECTION] = ErrorCorrectionLevel.Q; ByteMatrix matrix = qrwriter.encode(context, com.google.zxing.BarcodeFormat.QR_CODE, 440, 440, table); Texture2D pic = new Texture2D(440, 440, TextureFormat.RGBA32, false); Color whitecolor = new Color(238 / 255f, 245 / 255f, 212 / 255f); for (int x = 0; x < 440; x++) { for (int y = 0; y < 440; y++) { pic.SetPixel(x, y, matrix.get_Renamed(y, x) == 0 ? Color.black : whitecolor); } } if (gameLogo != null) { for (int x = 0; x < gameLogo.width; x++) { for (int y = 0; y < gameLogo.height; y++) { pic.SetPixel(x + offsetX, y + offsetY, gameLogo.GetPixel(x, y)); } } } pic.Apply(false); Sprite sp = Sprite.Create(pic, new Rect(0, 0, pic.width, pic.height), new Vector2(0.5f, 0.5f)); return(sp); }
private unsafe Bitmap ConvertByteMatrixToImage(ByteMatrix bm) { Bitmap image = CreateGrayscaleImage(bm.Width, bm.Height); BitmapData sourceData; sourceData = image.LockBits(new Rectangle(0, 0, image.Width, image.Height), ImageLockMode.ReadOnly, image.PixelFormat); int width = sourceData.Width; int height = sourceData.Height; int srcOffset = sourceData.Stride - width; byte *src = (byte *)sourceData.Scan0.ToPointer(); for (int y = 0; y < height; y++) { // for each pixel for (int x = 0; x < width; x++, src++) { *src = (byte)bm.Array[y][x]; } src += srcOffset; } image.UnlockBits(sourceData); return(image); }
private void GenQR(string ssconfig) { string qrText = ssconfig; QRCode code = ZXing.QrCode.Internal.Encoder.encode(qrText, ErrorCorrectionLevel.M); ByteMatrix m = code.Matrix; int blockSize = Math.Max(pictureBox1.Height / m.Height, 1); var qrWidth = m.Width * blockSize; var qrHeight = m.Height * blockSize; var dWidth = pictureBox1.Width - qrWidth; var dHeight = pictureBox1.Height - qrHeight; var maxD = Math.Max(dWidth, dHeight); pictureBox1.SizeMode = maxD >= 7 * blockSize ? PictureBoxSizeMode.Zoom : PictureBoxSizeMode.CenterImage; Bitmap drawArea = new Bitmap((m.Width * blockSize), (m.Height * blockSize)); using (Graphics g = Graphics.FromImage(drawArea)) { g.Clear(Color.White); using (Brush b = new SolidBrush(Color.Black)) { for (int row = 0; row < m.Width; row++) { for (int col = 0; col < m.Height; col++) { if (m[row, col] != 0) { g.FillRectangle(b, blockSize * row, blockSize * col, blockSize, blockSize); } } } } } pictureBox1.Image = drawArea; }
public void testApplyMaskPenaltyRule3() { { // Horizontal 00001011101. ByteMatrix matrix = new ByteMatrix(11, 1); matrix.set(0, 0, 0); matrix.set(1, 0, 0); matrix.set(2, 0, 0); matrix.set(3, 0, 0); matrix.set(4, 0, 1); matrix.set(5, 0, 0); matrix.set(6, 0, 1); matrix.set(7, 0, 1); matrix.set(8, 0, 1); matrix.set(9, 0, 0); matrix.set(10, 0, 1); Assert.AreEqual(40, MaskUtil.applyMaskPenaltyRule3(matrix)); } { // Horizontal 10111010000. ByteMatrix matrix = new ByteMatrix(11, 1); matrix.set(0, 0, 1); matrix.set(1, 0, 0); matrix.set(2, 0, 1); matrix.set(3, 0, 1); matrix.set(4, 0, 1); matrix.set(5, 0, 0); matrix.set(6, 0, 1); matrix.set(7, 0, 0); matrix.set(8, 0, 0); matrix.set(9, 0, 0); matrix.set(10, 0, 0); Assert.AreEqual(40, MaskUtil.applyMaskPenaltyRule3(matrix)); } { // Vertical 00001011101. ByteMatrix matrix = new ByteMatrix(1, 11); matrix.set(0, 0, 0); matrix.set(0, 1, 0); matrix.set(0, 2, 0); matrix.set(0, 3, 0); matrix.set(0, 4, 1); matrix.set(0, 5, 0); matrix.set(0, 6, 1); matrix.set(0, 7, 1); matrix.set(0, 8, 1); matrix.set(0, 9, 0); matrix.set(0, 10, 1); Assert.AreEqual(40, MaskUtil.applyMaskPenaltyRule3(matrix)); } { // Vertical 10111010000. ByteMatrix matrix = new ByteMatrix(1, 11); matrix.set(0, 0, 1); matrix.set(0, 1, 0); matrix.set(0, 2, 1); matrix.set(0, 3, 1); matrix.set(0, 4, 1); matrix.set(0, 5, 0); matrix.set(0, 6, 1); matrix.set(0, 7, 0); matrix.set(0, 8, 0); matrix.set(0, 9, 0); matrix.set(0, 10, 0); Assert.AreEqual(40, MaskUtil.applyMaskPenaltyRule3(matrix)); } }
/// <summary> /// 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. /// </summary> /// <param name="dataBits">The data bits.</param> /// <param name="maskPattern">The mask pattern.</param> /// <param name="matrix">The matrix.</param> public static void embedDataBits(BitArray dataBits, int maskPattern, ByteMatrix matrix) { int bitIndex = 0; int direction = -1; // Start from the right bottom cell. int x = matrix.Width - 1; int y = matrix.Height - 1; while (x > 0) { // Skip the vertical timing pattern. if (x == 6) { x -= 1; } while (y >= 0 && y < matrix.Height) { for (int i = 0; i < 2; ++i) { int xx = x - i; // Skip the cell if it's not empty. if (!isEmpty(matrix[xx, y])) { continue; } int bit; if (bitIndex < dataBits.Size) { bit = dataBits[bitIndex] ? 1 : 0; ++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[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); } }
// 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. internal static int applyMaskPenaltyRule1(ByteMatrix matrix) { return(applyMaskPenaltyRule1Internal(matrix, true) + applyMaskPenaltyRule1Internal(matrix, false)); }
/// <summary> /// 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). /// </summary> internal static int applyMaskPenaltyRule3(ByteMatrix matrix) { int penalty = 0; sbyte[][] array = matrix.Array; int width = matrix.Width; int height = matrix.Height; 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 += N3; } 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 += N3; } } } return penalty; }
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.Width - 8; ++i) { int bit = (i + 1) % 2; // Horizontal line. if (isEmpty(matrix[i, 6])) { matrix[i, 6] = bit; } // Vertical line. if (isEmpty(matrix[6, i])) { matrix[6, i] = bit; } } }
/// <summary> /// 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. /// </summary> internal static int applyMaskPenaltyRule1(ByteMatrix matrix) { return applyMaskPenaltyRule1Internal(matrix, true) + applyMaskPenaltyRule1Internal(matrix, false); }
private static void embedPositionDetectionPattern(int xStart, int yStart, ByteMatrix matrix) { for (int y = 0; y < 7; ++y) { for (int x = 0; x < 7; ++x) { matrix[xStart + x, yStart + y] = POSITION_DETECTION_PATTERN[y][x]; } } }
/// <summary> /// 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. /// </summary> internal static int applyMaskPenaltyRule4(ByteMatrix matrix) { int numDarkCells = 0; sbyte[][] array = matrix.Array; int width = matrix.Width; int height = matrix.Height; for (int y = 0; y < height; y++) { sbyte[] arrayY = array[y]; for (int x = 0; x < width; x++) { if (arrayY[x] == 1) { numDarkCells++; } } } int numTotalCells = matrix.Height * matrix.Width; double darkRatio = (double) numDarkCells / numTotalCells; int fivePercentVariances = (int)(Math.Abs(darkRatio - 0.5) * 20.0); // * 100.0 / 5.0 return fivePercentVariances * N4; }
/// <summary> /// Embed the lonely dark dot at left bottom corner. JISX0510:2004 (p.46) /// </summary> /// <param name="matrix">The matrix.</param> private static void embedDarkDotAtLeftBottomCorner(ByteMatrix matrix) { if (matrix[8, matrix.Height - 8] == 0) { throw new WriterException(); } matrix[8, matrix.Height - 8] = 1; }
private void ZXEncode(string content, int option) { System.String encoding = QRCodeConstantVariable.DefaultEncoding; ErrorCorrectionLevelInternal m_EcLevelInternal = ErrorCorrectionLevelInternal.H; QRCodeInternal qrCodeInternal = new QRCodeInternal(); // Step 1: Choose the mode (encoding). Mode mode = EncoderInternal.chooseMode(content, encoding); // Step 2: Append "bytes" into "dataBits" in appropriate encoding. BitVector dataBits = new BitVector(); EncoderInternal.appendBytes(content, mode, dataBits, encoding); // Step 3: Initialize QR code that can contain "dataBits". int numInputBytes = dataBits.sizeInBytes(); EncoderInternal.initQRCode(numInputBytes, m_EcLevelInternal, mode, qrCodeInternal); // 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 && !QRCodeConstantVariable.DefaultEncoding.Equals(encoding)) { CharacterSetECI eci = CharacterSetECI.getCharacterSetECIByName(encoding); if (eci != null) { EncoderInternal.appendECI(eci, headerAndDataBits); } } EncoderInternal.appendModeInfo(mode, headerAndDataBits); int numLetters = mode.Equals(Mode.BYTE)?dataBits.sizeInBytes():content.Length; EncoderInternal.appendLengthInfo(numLetters, qrCodeInternal.Version, mode, headerAndDataBits); headerAndDataBits.appendBitVector(dataBits); // Step 5: Terminate the bits properly. EncoderInternal.terminateBits(qrCodeInternal.NumDataBytes, headerAndDataBits); // Step 6: Interleave data bits with error correction code. BitVector finalBits = new BitVector(); EncoderInternal.interleaveWithECBytes(headerAndDataBits, qrCodeInternal.NumTotalBytes, qrCodeInternal.NumDataBytes, qrCodeInternal.NumRSBlocks, finalBits); if(option == 3) { return; } // Step 7: Choose the mask pattern and set to "QRCodeInternal". ByteMatrix matrix = new ByteMatrix(qrCodeInternal.MatrixWidth, qrCodeInternal.MatrixWidth); qrCodeInternal.MaskPattern = EncoderInternal.chooseMaskPattern(finalBits, qrCodeInternal.EcLevelInternal, qrCodeInternal.Version, matrix); // Step 8. Build the matrix and set it to "QRCodeInternal". MatrixUtil.buildMatrix(finalBits, qrCodeInternal.EcLevelInternal, qrCodeInternal.Version, qrCodeInternal.MaskPattern, matrix); qrCodeInternal.Matrix = matrix; }
private static void embedHorizontalSeparationPattern(int xStart, int yStart, ByteMatrix matrix) { for (int x = 0; x < 8; ++x) { if (!isEmpty(matrix[xStart + x, yStart])) { throw new WriterException(); } matrix[xStart + x, yStart] = 0; } }
private static void embedVerticalSeparationPattern(int xStart, int yStart, ByteMatrix matrix) { for (int y = 0; y < 7; ++y) { if (!isEmpty(matrix[xStart, yStart + y])) { throw new WriterException(); } matrix[xStart, yStart + y] = 0; } }
/// <summary> /// Embed position adjustment patterns if need be. /// </summary> /// <param name="version">The version.</param> /// <param name="matrix">The matrix.</param> private static void maybeEmbedPositionAdjustmentPatterns(Version version, ByteMatrix matrix) { if (version.VersionNumber < 2) { // The patterns appear if version >= 2 return; } int index = version.VersionNumber - 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[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); } } } }
/// <summary> /// Helper function for applyMaskPenaltyRule1. We need this for doing this calculation in both /// vertical and horizontal orders respectively. /// </summary> private static int applyMaskPenaltyRule1Internal(ByteMatrix matrix, bool isHorizontal) { int penalty = 0; int iLimit = isHorizontal ? matrix.Height : matrix.Width; int jLimit = isHorizontal ? matrix.Width : matrix.Height; sbyte[][] array = matrix.Array; for (int i = 0; i < iLimit; i++) { int numSameBitCells = 0; int prevBit = -1; for (int j = 0; j < jLimit; j++) { int bit = isHorizontal ? array[i][j] : array[j][i]; if (bit == prevBit) { numSameBitCells++; } else { if (numSameBitCells >= 5) { penalty += N1 + (numSameBitCells - 5); } numSameBitCells = 1; // Include the cell itself. prevBit = bit; } } if (numSameBitCells > 5) { penalty += N1 + (numSameBitCells - 5); } } return penalty; }
/// <summary> /// Embed position detection patterns and surrounding vertical/horizontal separators. /// </summary> /// <param name="matrix">The matrix.</param> 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.Width - pdpWidth, 0, matrix); // Left bottom corner. embedPositionDetectionPattern(0, matrix.Width - pdpWidth, matrix); // Embed horizontal separation patterns around the squares. const int hspWidth = 8; // Left top corner. embedHorizontalSeparationPattern(0, hspWidth - 1, matrix); // Right top corner. embedHorizontalSeparationPattern(matrix.Width - hspWidth, hspWidth - 1, matrix); // Left bottom corner. embedHorizontalSeparationPattern(0, matrix.Width - hspWidth, matrix); // Embed vertical separation patterns around the squares. const int vspSize = 7; // Left top corner. embedVerticalSeparationPattern(vspSize, 0, matrix); // Right top corner. embedVerticalSeparationPattern(matrix.Height - vspSize - 1, 0, matrix); // Left bottom corner. embedVerticalSeparationPattern(vspSize, matrix.Height - vspSize, matrix); }
/// <summary> /// 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. /// </summary> /// <param name="xStart">The x start.</param> /// <param name="yStart">The y start.</param> /// <param name="matrix">The matrix.</param> private static void embedPositionAdjustmentPattern(int xStart, int yStart, ByteMatrix matrix) { for (int y = 0; y < 5; ++y) { for (int x = 0; x < 5; ++x) { matrix[xStart + x, yStart + y] = POSITION_ADJUSTMENT_PATTERN[y][x]; } } }
public void testApplyMaskPenaltyRule4() { { // Dark cell ratio = 0% ByteMatrix matrix = new ByteMatrix(1, 1); matrix.set(0, 0, 0); Assert.AreEqual(100, MaskUtil.applyMaskPenaltyRule4(matrix)); } { // Dark cell ratio = 5% ByteMatrix matrix = new ByteMatrix(2, 1); matrix.set(0, 0, 0); matrix.set(0, 0, 1); Assert.AreEqual(0, MaskUtil.applyMaskPenaltyRule4(matrix)); } { // Dark cell ratio = 66.67% ByteMatrix matrix = new ByteMatrix(6, 1); matrix.set(0, 0, 0); matrix.set(1, 0, 1); matrix.set(2, 0, 1); matrix.set(3, 0, 1); matrix.set(4, 0, 1); matrix.set(5, 0, 0); Assert.AreEqual(30, MaskUtil.applyMaskPenaltyRule4(matrix)); } }
/// <summary> /// 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 /// </summary> /// <param name="version">The version.</param> /// <param name="matrix">The matrix.</param> public static void embedBasicPatterns(Version 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); }
private static int chooseMaskPattern(BitArray bits, ErrorCorrectionLevel ecLevel, Version version, ByteMatrix matrix) { int minPenalty = Int32.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; }
/// <summary> /// Embed type information. On success, modify the matrix. /// </summary> /// <param name="ecLevel">The ec level.</param> /// <param name="maskPattern">The mask pattern.</param> /// <param name="matrix">The matrix.</param> public static void embedTypeInfo(ErrorCorrectionLevel ecLevel, int maskPattern, ByteMatrix matrix) { BitArray typeInfoBits = new BitArray(); 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[typeInfoBits.Size - 1 - i] ? 1 : 0; // 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[x1, y1] = bit; if (i < 8) { // Right top corner. int x2 = matrix.Width - i - 1; int y2 = 8; matrix[x2, y2] = bit; } else { // Left bottom corner. int x2 = 8; int y2 = matrix.Height - 7 + (i - 8); matrix[x2, y2] = bit; } } }
/// <summary> /// Encodes the specified content. /// </summary> /// <param name="content">The content.</param> /// <param name="ecLevel">The ec level.</param> /// <param name="hints">The hints.</param> /// <returns></returns> public static QRCode encode(String content, ErrorCorrectionLevel ecLevel, IDictionary<EncodeHintType, object> hints) { // Determine what character encoding has been specified by the caller, if any #if !SILVERLIGHT || WINDOWS_PHONE String encoding = hints == null || !hints.ContainsKey(EncodeHintType.CHARACTER_SET) ? null : (String)hints[EncodeHintType.CHARACTER_SET]; if (encoding == null) { encoding = DEFAULT_BYTE_MODE_ENCODING; } bool generateECI = !DEFAULT_BYTE_MODE_ENCODING.Equals(encoding); #else // Silverlight supports only UTF-8 and UTF-16 out-of-the-box const string encoding = "UTF-8"; // caller of the method can only control if the ECI segment should be written // character set is fixed to UTF-8; but some scanners doesn't like the ECI segment bool generateECI = (hints != null && hints.ContainsKey(EncodeHintType.CHARACTER_SET)); #endif // Pick an encoding mode appropriate for the content. Note that this will not attempt to use // multiple modes / segments even if that were more efficient. Twould be nice. Mode mode = chooseMode(content, encoding); // This will store the header information, like mode and // length, as well as "header" segments like an ECI segment. BitArray headerBits = new BitArray(); // Append ECI segment if applicable if (mode == Mode.BYTE && generateECI) { CharacterSetECI eci = CharacterSetECI.getCharacterSetECIByName(encoding); if (eci != null) { var eciIsExplicitDisabled = (hints != null && hints.ContainsKey(EncodeHintType.DISABLE_ECI) ? (bool)hints[EncodeHintType.DISABLE_ECI] : false); if (!eciIsExplicitDisabled) { appendECI(eci, headerBits); } } } // (With ECI in place,) Write the mode marker appendModeInfo(mode, headerBits); // Collect data within the main segment, separately, to count its size if needed. Don't add it to // main payload yet. BitArray dataBits = new BitArray(); appendBytes(content, mode, dataBits, encoding); // Hard part: need to know version to know how many bits length takes. But need to know how many // bits it takes to know version. First we take a guess at version by assuming version will be // the minimum, 1: int provisionalBitsNeeded = headerBits.Size + mode.getCharacterCountBits(Version.getVersionForNumber(1)) + dataBits.Size; Version provisionalVersion = chooseVersion(provisionalBitsNeeded, ecLevel); // Use that guess to calculate the right version. I am still not sure this works in 100% of cases. int bitsNeeded = headerBits.Size + mode.getCharacterCountBits(provisionalVersion) + dataBits.Size; Version version = chooseVersion(bitsNeeded, ecLevel); BitArray headerAndDataBits = new BitArray(); headerAndDataBits.appendBitArray(headerBits); // Find "length" of main segment and write it int numLetters = mode == Mode.BYTE ? dataBits.SizeInBytes : content.Length; appendLengthInfo(numLetters, version, mode, headerAndDataBits); // Put data together into the overall payload headerAndDataBits.appendBitArray(dataBits); Version.ECBlocks ecBlocks = version.getECBlocksForLevel(ecLevel); int numDataBytes = version.TotalCodewords - ecBlocks.TotalECCodewords; // Terminate the bits properly. terminateBits(numDataBytes, headerAndDataBits); // Interleave data bits with error correction code. BitArray finalBits = interleaveWithECBytes(headerAndDataBits, version.TotalCodewords, numDataBytes, ecBlocks.NumBlocks); QRCode qrCode = new QRCode { ECLevel = ecLevel, Mode = mode, Version = version }; // Choose the mask pattern and set to "qrCode". int dimension = version.DimensionForVersion; ByteMatrix matrix = new ByteMatrix(dimension, dimension); int maskPattern = chooseMaskPattern(finalBits, ecLevel, version, matrix); qrCode.MaskPattern = maskPattern; // Build the matrix and set it to "qrCode". MatrixUtil.buildMatrix(finalBits, ecLevel, version, maskPattern, matrix); qrCode.Matrix = matrix; return qrCode; }
/// <summary> /// 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. /// </summary> /// <param name="version">The version.</param> /// <param name="matrix">The matrix.</param> public static void maybeEmbedVersionInfo(Version version, ByteMatrix matrix) { if (version.VersionNumber < 7) { // Version info is necessary if version >= 7. return; // Don't need version info. } BitArray versionInfoBits = new BitArray(); 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. var bit = versionInfoBits[bitIndex] ? 1 : 0; bitIndex--; // Left bottom corner. matrix[i, matrix.Height - 11 + j] = bit; // Right bottom corner. matrix[matrix.Height - 11 + j, i] = bit; } } }