public static BufferedImage toSingleQrCodeBufferedImage( String s, ErrorCorrectionLevel ec, int scaleFactor) throws WriterException { QRCode qrCode = new QRCode(); Encoder.encode(s, ec, qrCode); BufferedImage bufferedImage = MatrixToImageWriter.toBufferedImage(qrCode.getMatrix()); if (scaleFactor != 1) { int newWidth = bufferedImage.getWidth() * scaleFactor; int newHeight = bufferedImage.getHeight() * scaleFactor; Image image = bufferedImage.getScaledInstance(newWidth, newHeight, Image.SCALE_FAST); bufferedImage = ImageIoUtils.toBufferedImage(image); } return (bufferedImage); }
/** * Encode. * * @param text the text to encode * @return the image */ public Image encode(String text) { // Encode the text QRCode qrcode = new QRCode(); try { Encoder.encode(text, ErrorCorrectionLevel.H, qrcode); } catch (WriterException e) { e.printStackTrace(); } byte[][] matrix = qrcode.getMatrix().getArray(); int size = qrcode.getMatrixWidth() * scale; // Make the BufferedImage that are to hold the QRCode BufferedImage im = new BufferedImage(size, size, BufferedImage.TYPE_INT_RGB); im.createGraphics(); Graphics2D g = (Graphics2D) im.getGraphics(); g.setColor(Color.WHITE); g.fillRect(0, 0, size, size); // BitMatrix for validation BitMatrix bm = new BitMatrix(qrcode.getMatrixWidth()); // paint the image using the ByteMatrik for (int h = 0; h < qrcode.getMatrixWidth(); h++) { for (int w = 0; w < qrcode.getMatrixWidth(); w++) { // Find the colour of the dot if (matrix[h][w] == 0) g.setColor(Color.WHITE); else { g.setColor(Color.BLACK); bm.set(w, h); // build the BitMatrix } // Paint the dot g.fillRect(w * scale, h * scale, scale, scale); } } return im; }
// 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.getMatrix(); if (input == null) { throw new IllegalStateException(); } int inputWidth = input.getWidth(); int inputHeight = input.getHeight(); 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; }
/** * Generate a QR code with the payment information of a given size, optionally, with branding * * @param size A size of the QR code (without the branding) in pixels * @param paymentString A SPAYD string with payment information * @param hasBranging A flag that can be used to turn on/off branding * @return An image with the payment QR code * @throws IOException */ public static BufferedImage getQRCode(Integer size, String paymentString, boolean hasBranging) throws IOException { if (size == null) { size = SpaydConstants.defQRSize; } else if (size < SpaydConstants.minQRSize) { size = SpaydConstants.minQRSize; } else if (size > SpaydConstants.maxQRSize) { size = SpaydConstants.maxQRSize; } BitMatrix matrix = null; int h = size; int w = size; int barsize = -1; Writer writer = new MultiFormatWriter(); try { Map<EncodeHintType, Object> hints = new EnumMap<EncodeHintType, Object>(EncodeHintType.class); hints.put(EncodeHintType.CHARACTER_SET, "ISO-8859-1"); QRCode code = Encoder.encode(paymentString, ErrorCorrectionLevel.M, hints); hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M); barsize = size / (code.getMatrix().getWidth() + 8); matrix = writer.encode(paymentString, com.google.zxing.BarcodeFormat.QR_CODE, w, h, hints); } catch (com.google.zxing.WriterException e) { System.out.println(e.getMessage()); } if (matrix == null || barsize < 0) { throw new InvalidFormatException(); } BufferedImage image = MatrixToImageWriter.toBufferedImage(matrix); if (hasBranging) { Graphics2D g = (Graphics2D) image.getGraphics(); BasicStroke bs = new BasicStroke(2); g.setStroke(bs); g.setColor(Color.BLACK); g.drawLine(0, 0, w, 0); g.drawLine(0, 0, 0, h); g.drawLine(w, 0, w, h); g.drawLine(0, h, w, h); String str = "QR Platba"; int fontSize = size / 12; g.setFont(new Font("Verdana", Font.BOLD, fontSize)); FontMetrics fm = g.getFontMetrics(); Rectangle2D rect = fm.getStringBounds(str, g); g.setColor(Color.WHITE); g.fillRect( 2 * barsize, h - fm.getAscent(), (int) rect.getWidth() + 4 * barsize, (int) rect.getHeight()); int padding = 4 * barsize; BufferedImage paddedImage = new BufferedImage(w + 2 * padding, h + padding + (int) rect.getHeight(), image.getType()); Graphics2D g2 = paddedImage.createGraphics(); g2.setRenderingHint( RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_GASP); g2.setFont(new Font("Verdana", Font.BOLD, fontSize)); g2.setPaint(Color.WHITE); g2.fillRect(0, 0, paddedImage.getWidth(), paddedImage.getHeight()); g2.drawImage(image, padding, padding, Color.WHITE, null); g2.setColor(Color.BLACK); g2.drawString(str, padding + 4 * barsize, (int) (padding + h + rect.getHeight() - barsize)); image = paddedImage; } return image; }
public Renderable createImage( JasperReportsContext jasperReportsContext, JRComponentElement componentElement, QRCodeBean qrCodeBean, String message) { Map<EncodeHintType, Object> hints = new HashMap<EncodeHintType, Object>(); hints.put(EncodeHintType.CHARACTER_SET, QRCodeComponent.PROPERTY_DEFAULT_ENCODING); ErrorCorrectionLevel errorCorrectionLevel = qrCodeBean.getErrorCorrectionLevel().getErrorCorrectionLevel(); hints.put(EncodeHintType.ERROR_CORRECTION, errorCorrectionLevel); ByteMatrix matrix = null; SVGCanvasProvider provider = null; try { QRCode qrCode = Encoder.encode(message, errorCorrectionLevel, hints); matrix = qrCode.getMatrix(); provider = new SVGCanvasProvider(false, OrientationEnum.UP.getValue()); } catch (WriterException e) { throw new JRRuntimeException(e); } catch (BarcodeCanvasSetupException e) { throw new JRRuntimeException(e); } Document svgDoc = provider.getDOM(); Element svg = svgDoc.getDocumentElement(); int codeWidth = matrix.getWidth(); int codeHeight = matrix.getHeight(); JRStyle elementStyle = componentElement.getStyle(); int elementWidth = componentElement.getWidth() - (elementStyle == null ? 0 : (elementStyle.getLineBox().getLeftPadding() + elementStyle.getLineBox().getRightPadding())); int elementHeight = componentElement.getHeight() - (elementStyle == null ? 0 : (elementStyle.getLineBox().getTopPadding() + elementStyle.getLineBox().getBottomPadding())); int margin = qrCodeBean.getMargin() == null ? DEFAULT_MARGIN : qrCodeBean.getMargin(); int matrixWidth = codeWidth + 2 * margin; int matrixHeight = codeHeight + 2 * margin; // scaling to match the image size as closely as possible so that it looks good in html. // the resolution is taken into account because the html exporter rasterizes to a png // that has the same size as the svg. int resolution = JRPropertiesUtil.getInstance(jasperReportsContext) .getIntegerProperty( componentElement, BarcodeRasterizedImageProducer.PROPERTY_RESOLUTION, 300); int imageWidth = (int) Math.ceil(elementWidth * (resolution / 72d)); int imageHeight = (int) Math.ceil(elementHeight * (resolution / 72d)); double horizontalScale = ((double) imageWidth) / matrixWidth; double verticalScale = ((double) imageHeight) / matrixHeight; // we are scaling with integer units, not considering fractional coordinates for now int scale = Math.max(1, (int) Math.min(Math.ceil(horizontalScale), Math.ceil(verticalScale))); int qrWidth = scale * matrixWidth; int qrHeight = scale * matrixHeight; // scaling again because of the integer units double qrScale = Math.max(1d, Math.max(((double) qrWidth) / imageWidth, ((double) qrHeight) / imageHeight)); int svgWidth = (int) Math.ceil(qrScale * imageWidth); int svgHeight = (int) Math.ceil(qrScale * imageHeight); svg.setAttribute("width", String.valueOf(svgWidth)); svg.setAttribute("height", String.valueOf(svgHeight)); svg.setAttribute("viewBox", "0 0 " + svgWidth + " " + svgHeight); int xOffset = Math.max(0, (svgWidth - qrWidth) / 2); int yOffset = Math.max(0, (svgHeight - qrHeight) / 2); Color color = componentElement.getForecolor(); String fill = "#" + JRColorUtil.getColorHexa(color); String fillOpacity = color.getAlpha() < 255 ? Float.toString(((float) color.getAlpha()) / 255) : null; String rectangleSize = Integer.toString(scale); for (int x = 0; x < codeWidth; x++) { for (int y = 0; y < codeHeight; y++) { if (matrix.get(x, y) == 1) { Element element = svgDoc.createElementNS(svg.getNamespaceURI(), "rect"); element.setAttribute("x", String.valueOf(xOffset + scale * (x + margin))); element.setAttribute("y", String.valueOf(yOffset + scale * (y + margin))); element.setAttribute("width", rectangleSize); element.setAttribute("height", rectangleSize); element.setAttribute("fill", fill); if (fillOpacity != null) { element.setAttribute("fill-opacity", fillOpacity); } svgDoc.getFirstChild().appendChild(element); } } } Source source = new DOMSource(svgDoc); StringWriter outWriter = new StringWriter(); Result output = new StreamResult(outWriter); try { Transformer transformer = TransformerFactory.newInstance().newTransformer(); transformer.transform(source, output); } catch (TransformerException e) { throw new JRRuntimeException(e); } String svgString = outWriter.toString(); return new BatikRenderer(svgString, null); }