View Javadoc
1   /*
2    * Copyright (C) 2019 sw4j.org
3    *
4    * This program is free software: you can redistribute it and/or modify
5    * it under the terms of the GNU General Public License as published by
6    * the Free Software Foundation, either version 3 of the License, or
7    * (at your option) any later version.
8    *
9    * This program is distributed in the hope that it will be useful,
10   * but WITHOUT ANY WARRANTY; without even the implied warranty of
11   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12   * GNU General Public License for more details.
13   *
14   * You should have received a copy of the GNU General Public License
15   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16   */
17  package org.sw4j.tool.barcode.random.generator;
18  
19  import com.google.zxing.EncodeHintType;
20  import com.google.zxing.MultiFormatWriter;
21  import com.google.zxing.WriterException;
22  import com.google.zxing.client.j2se.MatrixToImageWriter;
23  import com.google.zxing.common.BitMatrix;
24  import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
25  import java.io.IOException;
26  import java.io.OutputStream;
27  import java.util.HashMap;
28  import java.util.Map;
29  import java.util.function.Consumer;
30  import java.util.logging.Level;
31  import java.util.logging.Logger;
32  import org.sw4j.tool.barcode.random.codedata.CodeData;
33  import org.sw4j.tool.barcode.random.config.CodeConfig;
34  import org.sw4j.tool.barcode.random.config.CodeType;
35  import org.sw4j.tool.barcode.random.config.EncodingConfig;
36  
37  /**
38   * <p>
39   * This is a {@link java.util.function.Consumer Consumer} for
40   * {@link org.sw4j.tool.barcode.random.generator.RandomIdent RandomIdent} which generates one barcode for a
41   * {@code RandomIdent}.
42   * </p>
43   * <p>
44   * This class is thread safe, as long as no barcodes for the same ident are generated.
45   * </p>
46   * @author Uwe Plonus &lt;u.plonus@gmail.com&gt;
47   */
48  public class BarcodeWriter implements Consumer<IdentValue> {
49  
50      /**
51       * <p>
52       * The logger of this class.
53       * </p>
54       */
55      private final Logger logger = Logger.getLogger(BarcodeWriter.class.getName());
56  
57      /**
58       * <p>
59       * The configuration for the barcode that should me generated.
60       * </p>
61       */
62      private final CodeConfig codeConfig;
63  
64      /**
65       * <p>
66       * The factories for the input and output stream.
67       * </p>
68       */
69      private final CodeData codeData;
70  
71      /**
72       * <p>
73       * Create a new instance with the given barcode config and output factories.
74       * </p>
75       * @param codeConfig the configuration for the barcode to generate.
76       * @param codeData the factories for the output files.
77       */
78      public BarcodeWriter(final CodeConfig codeConfig, final CodeData codeData) {
79          this.codeConfig = codeConfig;
80          this.codeData = codeData;
81      }
82  
83      /**
84       * <p>
85       * Generate the barcode for the given ident and configured barcode.
86       * </p>
87       * @param identValue the ident (and its values) for output.
88       */
89      @Override
90      public void accept(final IdentValue identValue) {
91          CodeType codeType = codeConfig.getType();
92          EncodingConfig codeEncoding = codeConfig.getEncoding();
93          String codeUrl = codeConfig.getUrl();
94          if (codeUrl == null) {
95              codeUrl = "{code}";
96          }
97          codeUrl = codeUrl.replace("{code}", identValue.getEncoded(codeEncoding));
98          try {
99              OutputStream os = codeData.getOutputForIdent(codeType, codeEncoding, identValue.getIdent(),
100                     codeConfig.getFiletype());
101             MultiFormatWriter codeWriter = new MultiFormatWriter();
102             Map<EncodeHintType, Object> encodingParameters = new HashMap<>();
103             encodingParameters.put(EncodeHintType.CHARACTER_SET, "utf-8");
104             setErrorCorrection(encodingParameters);
105             BitMatrix matrix = codeWriter.encode(codeUrl, codeType.getFormat(), codeConfig.getWidth(),
106                     codeConfig.getHeight(), encodingParameters);
107             MatrixToImageWriter.writeToStream(matrix, codeConfig.getFiletype(), os);
108         } catch (IOException | WriterException exc) {
109             logger.log(Level.WARNING,
110                     String.format("Writing of Code 'type: %s / encoding: %s / ident: %s' failed.",
111                             codeType.getType(), codeEncoding, identValue.getIdent()), exc);
112         }
113     }
114 
115     /**
116      * <p>
117      * Configure the barcode error correction depending on the bacode type.
118      * </p>
119      * @param encodingParameters the encoding parameters where the error correction should be set in.
120      */
121     private void setErrorCorrection(final Map<EncodeHintType, Object> encodingParameters) {
122         switch (codeConfig.getType()) {
123             case QRCODE:
124                 try {
125                     encodingParameters.put(EncodeHintType.ERROR_CORRECTION,
126                             ErrorCorrectionLevel.valueOf(codeConfig.getErrorCorrection()));
127                 } catch (IllegalArgumentException | NullPointerException exc) {
128                     encodingParameters.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
129                 }
130                 break;
131             case AZTEC:
132                 if (codeConfig.getErrorCorrection() == null || "".equals(codeConfig.getErrorCorrection())) {
133                     encodingParameters.put(EncodeHintType.ERROR_CORRECTION, "25");
134                 } else {
135                     encodingParameters.put(EncodeHintType.ERROR_CORRECTION, codeConfig.getErrorCorrection());
136                 }
137                 break;
138             default:
139                 // No error correction for the remaining codes
140         }
141     }
142 
143 }