2 * Copyright (c) 2018-2019. Developed by Hedgecode.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package org.hedgecode.chess.qrcode;
19 import java.awt.image.BufferedImage;
20 import java.io.IOException;
21 import java.io.OutputStream;
22 import java.nio.file.Path;
23 import java.nio.file.Paths;
24 import java.util.EnumMap;
27 import javax.imageio.ImageIO;
29 import com.google.zxing.EncodeHintType;
30 import com.google.zxing.WriterException;
31 import com.google.zxing.client.j2se.MatrixToImageWriter;
32 import com.google.zxing.common.BitMatrix;
33 import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
34 import com.google.zxing.qrcode.encoder.ByteMatrix;
35 import com.google.zxing.qrcode.encoder.Encoder;
36 import com.google.zxing.qrcode.encoder.QRCode;
38 import org.hedgecode.chess.ChessQRCodeConstants;
39 import org.hedgecode.chess.img.ImageFormat;
42 * Chess-specific QR Codes writer (image generator).
44 * @author Dmitry Samoshin aka gotty
46 public class ChessQRCodeWriter {
48 private static final int DEF_QUIET_ZONE_SIZE = 4;
49 private static final int DEF_QRCODE_BIT_SIZE = 250;
51 private static final ErrorCorrectionLevel DEF_ERR_CORR_LEVEL = ErrorCorrectionLevel.H; // todo: Q
53 private static ChessQRCodeWriter _instance = new ChessQRCodeWriter();
55 private ChessQRCodeWriter() {
58 public void write(ChessQRCodeMode mode, String contents, ImageFormat format, String qrCodeFilePath)
59 throws ChessQRCodeException
65 Paths.get(qrCodeFilePath)
69 public void write(ChessQRCodeMode mode, String contents, ImageFormat format, Path qrCodeFile)
70 throws ChessQRCodeException
87 int width, int height,
89 throws ChessQRCodeException
92 BufferedImage image = generate(mode, contents, width, height);
93 if (!ImageIO.write(image, format.name(), qrCodeFile.toFile())) {
94 throw new ChessQRCodeException(
95 ChessQRCodeException.Type.WRITE, "write.output.qrcode.file", qrCodeFile.toFile().getName()
98 } catch (IOException e) {
99 throw new ChessQRCodeException(
100 ChessQRCodeException.Type.WRITE, "write.output.qrcode.file", e.getMessage()
105 public void write(ChessQRCodeMode mode, String contents, ImageFormat format, OutputStream stream)
106 throws ChessQRCodeException
109 BufferedImage image = generate(mode, contents);
110 if (!ImageIO.write(image, format.name(), stream)) {
111 throw new ChessQRCodeException(
112 ChessQRCodeException.Type.WRITE, "write.output.qrcode.stream"
115 } catch (IOException e) {
116 throw new ChessQRCodeException(
117 ChessQRCodeException.Type.WRITE, "write.output.qrcode.stream", e.getMessage()
122 public BufferedImage generate(ChessQRCodeMode mode, String contents)
123 throws ChessQRCodeException
125 return generate(mode, contents, DEF_QRCODE_BIT_SIZE, DEF_QRCODE_BIT_SIZE);
128 public BufferedImage generate(ChessQRCodeMode mode, String contents, int width, int height)
129 throws ChessQRCodeException
131 BitMatrix bitMatrix = encode(
137 return MatrixToImageWriter.toBufferedImage(
142 private BitMatrix encode(
143 ChessQRCodeMode mode,
145 int width, int height,
146 Map<EncodeHintType,?> hints)
147 throws ChessQRCodeException
150 throw new ChessQRCodeException(
151 ChessQRCodeException.Type.WRITE, "write.qrcode.mode.null"
155 if (contents == null || contents.isEmpty()) {
156 throw new ChessQRCodeException(
157 ChessQRCodeException.Type.WRITE, "write.qrcode.contents.empty"
161 if (width < 0 || height < 0) { // todo
162 throw new ChessQRCodeException(
163 ChessQRCodeException.Type.WRITE, "write.qrcode.size.incorrect"
167 int quietZone = DEF_QUIET_ZONE_SIZE;
168 ErrorCorrectionLevel errorCorrectionLevel = DEF_ERR_CORR_LEVEL;
170 Map<EncodeHintType,Object> newHints = new EnumMap<>(EncodeHintType.class);
172 newHints.putAll(hints);
173 if (!hints.containsKey(EncodeHintType.CHARACTER_SET)) {
174 newHints.put(EncodeHintType.CHARACTER_SET, ChessQRCodeConstants.CHARSET.name());
176 if (hints.containsKey(EncodeHintType.ERROR_CORRECTION)) {
177 errorCorrectionLevel = ErrorCorrectionLevel.valueOf(
178 hints.get(EncodeHintType.ERROR_CORRECTION).toString()
181 if (hints.containsKey(EncodeHintType.MARGIN)) {
182 quietZone = Integer.parseInt(
183 hints.get(EncodeHintType.MARGIN).toString()
187 newHints.put(EncodeHintType.CHARACTER_SET, ChessQRCodeConstants.CHARSET.name());
191 String qrCodeText = mode.name().concat(contents);
195 qrCode = Encoder.encode(
196 qrCodeText, errorCorrectionLevel, hints
198 } catch (WriterException e) {
199 throw new ChessQRCodeException(
200 ChessQRCodeException.Type.WRITE, "write.zxing.qrcode.error", e.getMessage()
205 qrCode, width, height, quietZone
209 private BitMatrix renderMatrix(QRCode qrCode, int width, int height, int quietZone)
210 throws ChessQRCodeException
212 ByteMatrix byteMatrix =
213 ChessQRMatrixUtils.embedChessLogoPattern(
217 if (byteMatrix == null) {
218 throw new ChessQRCodeException(
219 ChessQRCodeException.Type.WRITE, "write.qrcode.chess.incorrect"
223 return ChessQRMatrixUtils.renderMatrix(
231 public static ChessQRCodeWriter getInstance() {
236 public static void main(String[] args) {
238 ChessQRCodeWriter.getInstance().write(
240 "rnbqkbnr/ppp1pppp/8/3p4/4P3/8/PPPP1PPP/RNBQKBNR w KQkq d6 0 2",
245 ChessQRCodeWriter.getInstance().write(
247 "1.e4 c6 2.d4 d5 3.Nc3 dxe4 4.Nxe4 Nd7 5.Ng5 Ngf6 6.Bd3 e6 7.N1f3 h6\n" +
248 "8.Nxe6 Qe7 9.O-O fxe6 10.Bg6+ Kd8 {Каспаров встряхнул головой} \n" +
249 "11.Bf4 b5 12.a4 Bb7 13.Re1 Nd5 14.Bg3 Kc8 15.axb5 cxb5 16.Qd3 Bc6 \n" +
250 "17.Bf5 exf5 18.Rxe7 Bxe7 19.c4 1-0",
255 } catch (ChessQRCodeException e) {
256 System.out.println("Could not generate QR Code, Exception: " + e.getMessage());