BarcodeWriter.java
/*
* Copyright (C) 2019 sw4j.org
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.sw4j.tool.barcode.random.generator;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.WriterException;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import java.io.IOException;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Consumer;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.sw4j.tool.barcode.random.codedata.CodeData;
import org.sw4j.tool.barcode.random.config.CodeConfig;
import org.sw4j.tool.barcode.random.config.CodeType;
import org.sw4j.tool.barcode.random.config.EncodingConfig;
/**
* <p>
* This is a {@link java.util.function.Consumer Consumer} for
* {@link org.sw4j.tool.barcode.random.generator.RandomIdent RandomIdent} which generates one barcode for a
* {@code RandomIdent}.
* </p>
* <p>
* This class is thread safe, as long as no barcodes for the same ident are generated.
* </p>
* @author Uwe Plonus <u.plonus@gmail.com>
*/
public class BarcodeWriter implements Consumer<IdentValue> {
/**
* <p>
* The logger of this class.
* </p>
*/
private final Logger logger = Logger.getLogger(BarcodeWriter.class.getName());
/**
* <p>
* The configuration for the barcode that should me generated.
* </p>
*/
private final CodeConfig codeConfig;
/**
* <p>
* The factories for the input and output stream.
* </p>
*/
private final CodeData codeData;
/**
* <p>
* Create a new instance with the given barcode config and output factories.
* </p>
* @param codeConfig the configuration for the barcode to generate.
* @param codeData the factories for the output files.
*/
public BarcodeWriter(final CodeConfig codeConfig, final CodeData codeData) {
this.codeConfig = codeConfig;
this.codeData = codeData;
}
/**
* <p>
* Generate the barcode for the given ident and configured barcode.
* </p>
* @param identValue the ident (and its values) for output.
*/
@Override
public void accept(final IdentValue identValue) {
CodeType codeType = codeConfig.getType();
EncodingConfig codeEncoding = codeConfig.getEncoding();
String codeUrl = codeConfig.getUrl();
if (codeUrl == null) {
codeUrl = "{code}";
}
codeUrl = codeUrl.replace("{code}", identValue.getEncoded(codeEncoding));
try {
OutputStream os = codeData.getOutputForIdent(codeType, codeEncoding, identValue.getIdent(),
codeConfig.getFiletype());
MultiFormatWriter codeWriter = new MultiFormatWriter();
Map<EncodeHintType, Object> encodingParameters = new HashMap<>();
encodingParameters.put(EncodeHintType.CHARACTER_SET, "utf-8");
setErrorCorrection(encodingParameters);
BitMatrix matrix = codeWriter.encode(codeUrl, codeType.getFormat(), codeConfig.getWidth(),
codeConfig.getHeight(), encodingParameters);
MatrixToImageWriter.writeToStream(matrix, codeConfig.getFiletype(), os);
} catch (IOException | WriterException exc) {
logger.log(Level.WARNING,
String.format("Writing of Code 'type: %s / encoding: %s / ident: %s' failed.",
codeType.getType(), codeEncoding, identValue.getIdent()), exc);
}
}
/**
* <p>
* Configure the barcode error correction depending on the bacode type.
* </p>
* @param encodingParameters the encoding parameters where the error correction should be set in.
*/
private void setErrorCorrection(final Map<EncodeHintType, Object> encodingParameters) {
switch (codeConfig.getType()) {
case QRCODE:
try {
encodingParameters.put(EncodeHintType.ERROR_CORRECTION,
ErrorCorrectionLevel.valueOf(codeConfig.getErrorCorrection()));
} catch (IllegalArgumentException | NullPointerException exc) {
encodingParameters.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
}
break;
case AZTEC:
if (codeConfig.getErrorCorrection() == null || "".equals(codeConfig.getErrorCorrection())) {
encodingParameters.put(EncodeHintType.ERROR_CORRECTION, "25");
} else {
encodingParameters.put(EncodeHintType.ERROR_CORRECTION, codeConfig.getErrorCorrection());
}
break;
default:
// No error correction for the remaining codes
}
}
}