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.img.ImageFormat;
41 * Chess-specific QR Codes writer (image generator).
43 * @author Dmitry Samoshin aka gotty
45 public class ChessQRCodeWriter {
47 private static final int DEF_QUIET_ZONE_SIZE = 4;
48 private static final int DEF_QRCODE_BIT_SIZE = 250;
49 private static final int MIN_QRCODE_BIT_SIZE = 50;
51 private static final ErrorCorrectionLevel DEF_ERR_CORR_LEVEL = ErrorCorrectionLevel.H; // todo: Q
53 private static ChessQRCodeWriter _instance = new ChessQRCodeWriter();
55 protected 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 protected 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 (Math.min(width, height) < MIN_QRCODE_BIT_SIZE) { // todo: check for Version
162 throw new ChessQRCodeException(
163 ChessQRCodeException.Type.WRITE, "write.qrcode.size.incorrect"
167 String qrCodeContents = mode.name().concat(contents);
169 int quietZone = DEF_QUIET_ZONE_SIZE;
170 ErrorCorrectionLevel errorCorrectionLevel = DEF_ERR_CORR_LEVEL;
172 Map<EncodeHintType,Object> newHints = new EnumMap<>(EncodeHintType.class);
174 newHints.putAll(hints);
175 if (!hints.containsKey(EncodeHintType.CHARACTER_SET)) {
176 newHints.put(EncodeHintType.CHARACTER_SET, ChessQRCodeConstants.CHARSET.name());
178 if (hints.containsKey(EncodeHintType.ERROR_CORRECTION)) {
179 errorCorrectionLevel = ErrorCorrectionLevel.valueOf(
180 hints.get(EncodeHintType.ERROR_CORRECTION).toString()
183 if (hints.containsKey(EncodeHintType.MARGIN)) {
184 quietZone = Integer.parseInt(
185 hints.get(EncodeHintType.MARGIN).toString()
189 newHints.put(EncodeHintType.CHARACTER_SET, ChessQRCodeConstants.CHARSET.name());
195 qrCode = Encoder.encode(
196 qrCodeContents, 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());