ZxingGenerator.java

package org.europa.together.application;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.BinaryBitmap;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatReader;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.common.HybridBinarizer;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import java.io.File;
import java.io.FileInputStream;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Map;
import javax.imageio.ImageIO;
import org.europa.together.business.Logger;
import org.europa.together.business.QrCodeGenerator;
import org.europa.together.domain.LogLevel;
import org.springframework.stereotype.Repository;

/**
 * Implementation of the QR Code Generator.
 */
@Repository
public class ZxingGenerator implements QrCodeGenerator {

    private static final long serialVersionUID = 7L;
    private static final Logger LOGGER = new LogbackLogger(ZxingGenerator.class);

    private final String charset;
    private int dimensionHeight;
    private int dimensionWidth;
    private String fileOutputPath;
    private final Map<EncodeHintType, Object> errorMap = new HashMap<>();

    /**
     * Constructor.
     */
    public ZxingGenerator() {
        errorMap.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.L);
        charset = "UTF-8";
        LOGGER.log("instance class", LogLevel.INFO);
    }

    @Override
    public void setup(final String fileOutputPath, final int dimensions) {
        this.dimensionHeight = dimensions;
        this.dimensionWidth = dimensions;
        this.fileOutputPath = fileOutputPath;
    }

    @Override
    public String generateDataForvCard(final Map<String, String> contact) {
        String data = null;
        if (contact == null || contact.isEmpty()) {
            LOGGER.log("Contact information are empty.", LogLevel.WARN);
        } else {
            LocalDateTime now = LocalDateTime.now();
            String dateStr
                    = now.format(DateTimeFormatter.ofPattern("yyyy-mm-dd hh:mm:ss"));
            data = "BEGIN:VCARD\n VERSION:3.0\n PROFILE:VCARD\n"
                    + "N:" + contact.get("name") + ";"
                    + contact.get("surname") + ";;" + contact.get("gender") + ";\n"
                    + "FN:" + contact.get("surname") + " " + contact.get("name") + "\n"
                    + "ORG:" + contact.get("organization") + "\n"
                    + "TITLE:" + contact.get("title") + "\n"
                    + "TEL;TYPE=WORK,CELL:" + contact.get("work-mobile") + "\n"
                    + "TEL;TYPE=WORK,VOICE:" + contact.get("work-phone") + "\n"
                    + "TEL;TYPE=HOME,CELL:" + contact.get("home-mobile") + "\n"
                    + "TEL;TYPE=HOME,VOICE:" + contact.get("home-phone") + "\n"
                    + "ADR;TYPE=WORK,PREF:;;" + contact.get("home-street") + ";"
                    + contact.get("home-city") + ";" + contact.get("home-state") + ";"
                    + contact.get("home-zipcode") + ";" + contact.get("home-country") + "\n"
                    + "LABEL;TYPE=WORK,PREF:" + contact.get("work-street") + "\\n"
                    + contact.get("work-city") + "\\, " + contact.get("work-state") + " "
                    + contact.get("work-zipcode") + "\\n " + contact.get("work-country") + "\n"
                    + "ADR;TYPE=WORK,PREF:;;" + contact.get("work-street") + ";"
                    + contact.get("work-city") + ";" + contact.get("work-state") + ";"
                    + contact.get("work-zipcode") + ";" + contact.get("work-country") + "\n"
                    + "ADR;TYPE=HOME:;;" + contact.get("home-street") + ";"
                    + contact.get("home-city") + ";" + contact.get("home-state") + ";"
                    + contact.get("home-zipcode") + ";" + contact.get("home-country") + "\n"
                    + "LABEL;TYPE=HOME:" + contact.get("home-street") + "\\n"
                    + contact.get("home-city") + "\\, " + contact.get("home-state") + " "
                    + contact.get("home-zipcode") + "\\n " + contact.get("home-country") + "\n"
                    + "URL:" + contact.get("homepage") + "\n"
                    + "EMAIL:" + contact.get("e-mail") + "\n"
                    + "REV:" + dateStr + "\nEND:VCARD";
        }
        return data;
    }

    @Override
    public String generateDataForCalendarEvent(final String event,
            final ZonedDateTime start, final ZonedDateTime end) {
        String data = "BEGIN:VEVENT\n"
                + "SUMMARY:" + event
                + "\n DTSTART:" + start.format(DateTimeFormatter.ofPattern("yyyy-mm-dd hh:mm:ss"))
                + "\n DTEND: " + end.format(DateTimeFormatter.ofPattern("yyyy-mm-dd hh:mm:ss"))
                + "\n END:VEVENT";
        return data;
    }

    @Override
    public String generateDataForUrl(final String url) {
        String data = url.replace("//", "");
        return "URLTO:" + data;
    }

    @Override
    public String generateDataForGeoLocation(final String latitude, final String longitude) {
        return "geo:" + latitude + "," + longitude + ",100";
    }

    @Override
    public boolean encode(final String data) {
        boolean success = false;
        try {
            BitMatrix matrix = new MultiFormatWriter().encode(
                    new String(data.getBytes(charset), charset),
                    BarcodeFormat.QR_CODE,
                    dimensionWidth,
                    dimensionHeight,
                    errorMap);
            MatrixToImageWriter.writeToPath(matrix, "png", Paths.get(fileOutputPath));
            success = true;
        } catch (Exception ex) {
            LOGGER.catchException(ex);
        }
        return success;
    }

    @Override
    public String decode(final File qrCode) {
        String decode = null;
        try {
            BinaryBitmap binaryBitmap
                    = new BinaryBitmap(
                            new HybridBinarizer(
                                    new BufferedImageLuminanceSource(
                                            ImageIO.read(new FileInputStream(qrCode)))));
            decode = new MultiFormatReader().decode(binaryBitmap).getText();
        } catch (Exception ex) {
            LOGGER.catchException(ex);
        }
        return decode;
    }
}