All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.primefaces.application.resource.QRCodeHandler Maven / Gradle / Ivy

/*
 * The MIT License
 *
 * Copyright (c) 2009-2023 PrimeTek Informatics
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package org.primefaces.application.resource;

import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Map;
import java.util.Objects;

import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.imageio.ImageIO;

import org.primefaces.util.Constants;
import org.primefaces.util.LangUtils;

import io.nayuki.qrcodegen.QrCode;
import io.nayuki.qrcodegen.QrCode.Ecc;

public class QRCodeHandler extends BaseDynamicContentHandler {

    @Override
    public void handle(FacesContext context) throws IOException {
        Map params = context.getExternalContext().getRequestParameterMap();
        ExternalContext externalContext = context.getExternalContext();
        String sessionKey = params.get(Constants.DYNAMIC_CONTENT_PARAM);
        Map session = externalContext.getSessionMap();
        Map barcodeMapping = (Map) session.get(Constants.BARCODE_MAPPING);
        if (barcodeMapping == null) {
            return;
        }

        String value = barcodeMapping.get(sessionKey);
        if (value == null) {
            return;
        }

        boolean cache = Boolean.parseBoolean(params.get(Constants.DYNAMIC_CONTENT_CACHE_PARAM));

        QrCode qrCode = QrCode.encodeText(value, getErrorCorrection(params.get("qrec")));
        if ("png".equals(params.get("fmt"))) {
            externalContext.setResponseContentType("image/png");
            ImageIO.write(toImage(qrCode, 12, 0), "png", externalContext.getResponseOutputStream());
        }
        else {
            externalContext.setResponseContentType("image/svg+xml");
            externalContext.getResponseOutputWriter().write(toSvgString(qrCode, 0, "#FFFFFF", "#000000"));
        }
        handleCache(externalContext, cache);
        externalContext.setResponseStatus(200);
        externalContext.responseFlushBuffer();
        context.responseComplete();
    }

    protected Ecc getErrorCorrection(final String value) {
        switch (LangUtils.isNotBlank(value) ? value : Constants.EMPTY_STRING) {
            case "M":
                return Ecc.MEDIUM;
            case "Q":
                return Ecc.QUARTILE;
            case "H":
                return Ecc.HIGH;
            default:
                return Ecc.LOW;
        }
    }

    protected BufferedImage toImage(QrCode qr, int scale, int border) {
        return toImage(qr, scale, border, 0xFFFFFF, 0x000000);
    }

    /**
     * Returns a raster image depicting the specified QR Code, with
     * the specified module scale, border modules, and module colors.
     * 

For example, scale=10 and border=4 means to pad the QR Code with 4 light border * modules on all four sides, and use 10×10 pixels to represent each module. * @param qr the QR Code to render (not {@code null}) * @param scale the side length (measured in pixels, must be positive) of each module * @param border the number of border modules to add, which must be non-negative * @param lightColor the color to use for light modules, in 0xRRGGBB format * @param darkColor the color to use for dark modules, in 0xRRGGBB format * @return a new image representing the QR Code, with padding and scaling * @throws NullPointerException if the QR Code is {@code null} * @throws IllegalArgumentException if the scale or border is out of range, or if * {scale, border, size} cause the image dimensions to exceed Integer.MAX_VALUE */ protected BufferedImage toImage(QrCode qr, int scale, int border, int lightColor, int darkColor) { Objects.requireNonNull(qr); if (scale <= 0 || border < 0) { throw new IllegalArgumentException("Value out of range"); } if (border > Integer.MAX_VALUE / 2 || qr.size + border * 2L > Integer.MAX_VALUE / scale) { throw new IllegalArgumentException("Scale or border too large"); } BufferedImage result = new BufferedImage((qr.size + border * 2) * scale, (qr.size + border * 2) * scale, BufferedImage.TYPE_INT_RGB); for (int y = 0; y < result.getHeight(); y++) { for (int x = 0; x < result.getWidth(); x++) { boolean color = qr.getModule(x / scale - border, y / scale - border); result.setRGB(x, y, color ? darkColor : lightColor); } } return result; } /** * Returns a string of SVG code for an image depicting the specified QR Code, with the specified * number of border modules. The string always uses Unix newlines (\n), regardless of the platform. * @param qr the QR Code to render (not {@code null}) * @param border the number of border modules to add, which must be non-negative * @param lightColor the color to use for light modules, in any format supported by CSS, not {@code null} * @param darkColor the color to use for dark modules, in any format supported by CSS, not {@code null} * @return a string representing the QR Code as an SVG XML document * @throws NullPointerException if any object is {@code null} * @throws IllegalArgumentException if the border is negative */ protected String toSvgString(QrCode qr, int border, String lightColor, String darkColor) { Objects.requireNonNull(qr); Objects.requireNonNull(lightColor); Objects.requireNonNull(darkColor); if (border < 0) { throw new IllegalArgumentException("Border must be non-negative"); } long brd = border; StringBuilder sb = new StringBuilder() .append("\n") .append("\n") .append(String.format("", qr.size + brd * 2)) .append("\n") .append("\t\n") .append("\t\n").append("\n").toString(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy