public static void writeToFile(COMMON.ByteMatrix matrix, System.Drawing.Imaging.ImageFormat format, string file) { System.Drawing.Imaging.EncoderParameters eps = new System.Drawing.Imaging.EncoderParameters(); eps.Param[0] = new System.Drawing.Imaging.EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 100L); Bitmap bmap = toBitmap(matrix); bmap.Save(file, format); }
public static Bitmap Encode_Code_39(string content) { Code39Writer ean8w = new Code39Writer(); ByteMatrix byteMatrix = ean8w.encode(content, BarcodeFormat.CODE_39, 400, 38); Bitmap bitmap = ByteMatrixToBitmap(byteMatrix); return(bitmap); }
// 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.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 += 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; }
public QRCode() { mode = null; ecLevel = null; version = -1; matrixWidth = -1; maskPattern = -1; numTotalBytes = -1; numDataBytes = -1; numECBytes = -1; numRSBlocks = -1; matrix = null; }
public Bitmap toBitmap(ByteMatrix matrix) { int width = matrix.Width; int height = matrix.Height; Bitmap bmap = new Bitmap(width, height, System.Drawing.Imaging.PixelFormat.Format32bppArgb); for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { bmap.SetPixel(x, y, matrix.get_Renamed(x, y) != -1 ? ColorTranslator.FromHtml("0xFF000000") : ColorTranslator.FromHtml("0xFFFFFFFF")); } } return bmap; }
public static Bitmap toBitmap(ByteMatrix matrix) { int width = matrix.Width; int height = matrix.Height; Bitmap bmap = new Bitmap(width, height, System.Drawing.Imaging.PixelFormat.Format32bppArgb); for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { bmap.SetPixel(x, y, matrix.get_Renamed(x, y) != -1 ? ColorTranslator.FromHtml("0xFF000000") : ColorTranslator.FromHtml("0xFFFFFFFF")); } } return(bmap); }
// 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 CreateSquares(ByteMatrix byteMatrix, int squareSize) { squares = new Square[(byteMatrix.Width / squareSize) + 1, (byteMatrix.Height / squareSize) + 1]; for (int y = 0, cntY = 0; y < byteMatrix.Height; y+=squareSize, cntY++) { for (int x = 0, cntX = 0; x < byteMatrix.Width; x+=squareSize, cntX++) { Color clr; if (byteMatrix.Array[x][y] == 0) clr = Color.Black; else clr = Color.White; squares[cntX, cntY] = new Square( new Size(squareSize, squareSize), new System.Drawing.Point(cntX * squareSize, cntY * squareSize) ); squares[cntX, cntY].Color = clr; } } }
// Encode "bytes" with the error correction level "getECLevel". The encoding mode will be chosen // internally by chooseMode(). On success, store the result in "qrCode" and return true. // 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) { // Step 1: Choose the mode (encoding). Mode mode = chooseMode(content); // Step 2: Append "bytes" into "dataBits" in appropriate encoding. BitVector dataBits = new BitVector(); appendBytes(content, mode, 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(); appendModeInfo(qrCode.getMode(), headerAndDataBits); appendLengthInfo(content.Length, qrCode.getVersion(), qrCode.getMode(), 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()); } }
private static int chooseMaskPattern(BitVector bits, ErrorCorrectionLevel ecLevel, int version,ByteMatrix matrix) { try{ 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; }catch(Exception e){ throw new ReaderException(e.Message); } }
// 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; }
// 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(y, x))) { // -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> /// What to do when the selection changes in the QR Code site list: /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void cmboExportSiteQR_SelectedIndexChanged(object sender, EventArgs e) { // Asbestos underpants: try { // Get the current selection of the combo box and make sure it // isn't empty: String site = (string)cmboExportSiteQR.Text; if (!String.IsNullOrEmpty(site)) { // Ask the main form to give us the site parameters for this site. // Since the main form has all the code to do this, we'll ask it // to do the dirty work. SiteParameters siteParams = caller.GetSiteParamsForQRCode(site); // Now we'll generate the text we'll embed into the QR Code. We want // this to be as compact as we can get it, so our "headings" will be // single letters. We'll start off with an identifying header so the // QR Code reader will know the format of our string. We delimite the // string with pipes, which aren't allowed in any of our fields. We // want this to match as closely to the values of the XML export file // for consistency. That means the hash engine and the character // limit fields will need some tweaking. StringBuilder sb = new StringBuilder(); sb.Append("CRYPTNOSv1|" + "S:" + siteParams.Site + "|" + "H:" + HashEngine.HashEnumStringToDisplayHash(siteParams.Hash) + "|" + "I:" + siteParams.Iterations.ToString() + "|" + "C:" + siteParams.CharTypes.ToString() + "|L:"); if (siteParams.CharLimit < 0) sb.Append("0"); else sb.Append(siteParams.CharLimit.ToString()); // Now that we've built our string, use the QRCodeWriter from ZXing to // build the QR Code image and assign the bitmap to the picture box: byteMatrix = qrCodeWriter.encode(sb.ToString(), BarcodeFormat.QR_CODE, 200, 200); pictureBox1.Image = byteMatrix.ToBitmap(); } // If the selection in the combo box wasn't useful, empty the picture box: else pictureBox1.Image = null; } // Similarly, if anything blew up, empty the picture box: catch { pictureBox1.Image = null; } }
// 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.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.get(y, xx))) { 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) { int mask = MaskUtil.getDataMaskBit(maskPattern, xx, y); bit ^= mask; } matrix.set(y, xx, 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. public static int applyMaskPenaltyRule1(ByteMatrix matrix) { return applyMaskPenaltyRule1Internal(matrix, true) + applyMaskPenaltyRule1Internal(matrix, false); }
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.Length != 1) { throw new WriterException("Bad horizontal separation pattern"); } for (int x = 0; x < 8; ++x) { if (!isEmpty(matrix.get(yStart, xStart + x))) { throw new WriterException(); } matrix.set(yStart, xStart + x, HORIZONTAL_SEPARATION_PATTERN[0][x]); } }
// 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.get(yStart + y, xStart + x))) { throw new WriterException(); } matrix.set(yStart + y, xStart + x, POSITION_ADJUSTMENT_PATTERN[y][x]); } } }
// Embed the lonely dark dot at left bottom corner. JISX0510:2004 (p.46) private static void embedDarkDotAtLeftBottomCorner(ByteMatrix matrix) { if (matrix.get(matrix.height() - 8, 8) == 0) { throw new WriterException(); } matrix.set(matrix.height() - 8, 8, 1); }
// 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(matrix.height() - 11 + j, i, bit); // Right bottom corner. matrix.set(i, matrix.height() - 11 + j, bit); } } }
// 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(y1, x1, bit); if (i < 8) { // Right top corner. int x2 = matrix.width() - i - 1; int y2 = 8; matrix.set(y2, x2, bit); } else { // Left bottom corner. int x2 = 8; int y2 = matrix.height() - 7 + (i - 8); matrix.set(y2, x2, bit); } } }
// 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; }
private int GetSizeOf1Square(ByteMatrix byteMatrix) { // The first line is compose initaly by seven black square int size = 0; // Try if it's a border (sound's like all pixel are white [-1]) int row = 0; bool found = false; while (!found) { for (int x = 0; x < byteMatrix.Array[row].Length; x++) { if (byteMatrix.Array[row][x] == 0) { found = true; break; } } row++; } //while (byteMatrix.Array[row][size++] == -1) ; while (byteMatrix.Array[row][size++] == 0) ; return ((size - 1) / 7); }
// 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.height() : matrix.width(); int jLimit = isHorizontal ? matrix.width() : matrix.height(); 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; }
// 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)); }
private ByteMatrix QRCodeGen(string text, int width, int height) { try { QRCodeWriter writer = new QRCodeWriter(0); Hashtable hints = new Hashtable(); hints.Add(EncodeHintType.ERROR_CORRECTION, com.google.zxing.qrcode.decoder.ErrorCorrectionLevel.M); hints.Add("Version", "7"); ByteMatrix _matrix = writer.encode(text, BarcodeFormat.QR_CODE, width, height, hints); #region Supress border white line int row = -1; int col = -1; int endRow = 0; int endCol = 0; bool isWhiteLine = true; while (isWhiteLine) { row++; for (int i = 0; i < _matrix.Width; i++) { if (_matrix.Array[row][i] == 0) { isWhiteLine = false; break; } } } isWhiteLine = true; endRow = _matrix.Height; while (isWhiteLine) { endRow--; for (int i = 0; i < _matrix.Width; i++) { if (_matrix.Array[endRow][i] == 0) { isWhiteLine = false; break; } } } isWhiteLine = true; while (isWhiteLine) { col++; for (int i = 0; i < _matrix.Height; i++) { if (_matrix.Array[i][col] == 0) { isWhiteLine = false; break; } } } isWhiteLine = true; endCol = _matrix.Width; while (isWhiteLine) { endCol--; for (int i = 0; i < _matrix.Height; i++) { if (_matrix.Array[i][endCol] == 0) { isWhiteLine = false; break; } } } #endregion ByteMatrix final = new ByteMatrix(endCol - col, endRow - row); for (int y = row; y < endRow; y++) { for (int x = col; x < endCol; x++) { final.Array[x - col][y - row] = _matrix.Array[x][y]; } } return final; } catch (Exception ex) { return null; } }
// 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) { try { // 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); }catch(Exception e){ throw new WriterException (e.Message); } }
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.get(yStart + y, xStart + x))) { throw new WriterException(); } matrix.set(yStart + y, xStart + x, POSITION_DETECTION_PATTERN[y][x]); } } }
// 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) { try{ 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); }catch(Exception e){ throw new WriterException(e.Message); } }
public static void writeToFile(ByteMatrix matrix, System.Drawing.Imaging.ImageFormat format, string file) { Bitmap bmap = toBitmap(matrix); bmap.Save(file, format); }
// 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.width() - pdpWidth, 0, matrix); // Left bottom corner. embedPositionDetectionPattern(0, matrix.width() - 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.width() - hspWidth, hspWidth - 1, matrix); // Left bottom corner. embedHorizontalSeparationPattern(0, matrix.width() - 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.height() - vspSize - 1, 0, matrix); // Left bottom corner. embedVerticalSeparationPattern(vspSize, matrix.height() - vspSize, matrix); }
// This takes ownership of the 2D array. public void setMatrix(ByteMatrix value) { matrix = value; }
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 (!isValidValue(matrix.get(6, i))) { throw new WriterException(); } if (isEmpty(matrix.get(6, i))) { matrix.set(6, i, bit); } // Vertical line. if (!isValidValue(matrix.get(i, 6))) { throw new WriterException(); } if (isEmpty(matrix.get(i, 6))) { matrix.set(i, 6, bit); } } }
// 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.width(); int inputHeight = input.height(); 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 accomodate 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(outputHeight, outputWidth); 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], unchecked((sbyte)255)); } // 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] = unchecked((sbyte) 255); } // 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 : unchecked((sbyte) 255); 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] = unchecked((sbyte) 255); } // 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], unchecked((sbyte) 255)); } return output; }
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.Length != 7) { throw new WriterException("Bad vertical separation pattern"); } for (int y = 0; y < 7; ++y) { if (!isEmpty(matrix.get(yStart + y, xStart))) { throw new WriterException(); } matrix.set(yStart + y, xStart, VERTICAL_SEPARATION_PATTERN[y][0]); } }