Example #1
0
  /**
   * Convert the ByteMatrix to BitMatrix.
   *
   * @param matrix The input matrix.
   * @return The output matrix.
   */
  private static BitMatrix convertByteMatrixToBitMatrix(ByteMatrix matrix) {
    int matrixWidgth = matrix.getWidth();
    int matrixHeight = matrix.getHeight();

    BitMatrix 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.get(i, j) == 1) {
          output.set(i, j);
        }
      }
    }

    return output;
  }
  // 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;
  }
  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);
  }