--- /dev/null
+/*
+ * Copyright (c) 2018-2019. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.qrcode;
+
+import java.awt.image.BufferedImage;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.EnumMap;
+import java.util.Map;
+
+import javax.imageio.ImageIO;
+
+import com.google.zxing.EncodeHintType;
+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 com.google.zxing.qrcode.encoder.ByteMatrix;
+import com.google.zxing.qrcode.encoder.Encoder;
+import com.google.zxing.qrcode.encoder.QRCode;
+
+import org.hedgecode.chess.ChessQRCodeConstants;
+import org.hedgecode.chess.img.ImageFormat;
+
+/**
+ * Chess-specific QR Codes writer (image generator).
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public class ChessQRCodeWriter {
+
+ private static final int DEF_QUIET_ZONE_SIZE = 4;
+ private static final int DEF_QRCODE_BIT_SIZE = 250;
+
+ private static final ErrorCorrectionLevel DEF_ERR_CORR_LEVEL = ErrorCorrectionLevel.H; // todo: Q
+
+ private static ChessQRCodeWriter _instance = new ChessQRCodeWriter();
+
+ private ChessQRCodeWriter() {
+ }
+
+ public void write(ChessQRCodeMode mode, String contents, ImageFormat format, String qrCodeFilePath)
+ throws ChessQRCodeException
+ {
+ write(
+ mode,
+ contents,
+ format,
+ Paths.get(qrCodeFilePath)
+ );
+ }
+
+ public void write(ChessQRCodeMode mode, String contents, ImageFormat format, Path qrCodeFile)
+ throws ChessQRCodeException
+ {
+ write(
+ mode,
+ contents,
+ format,
+ DEF_QRCODE_BIT_SIZE,
+ DEF_QRCODE_BIT_SIZE,
+ qrCodeFile
+ );
+ }
+
+
+ public void write(
+ ChessQRCodeMode mode,
+ String contents,
+ ImageFormat format,
+ int width, int height,
+ Path qrCodeFile)
+ throws ChessQRCodeException
+ {
+ try {
+ BufferedImage image = generate(mode, contents, width, height);
+ if (!ImageIO.write(image, format.name(), qrCodeFile.toFile())) {
+ throw new ChessQRCodeException(
+ ChessQRCodeException.Type.WRITE, "write.output.qrcode.file", qrCodeFile.toFile().getName()
+ );
+ }
+ } catch (IOException e) {
+ throw new ChessQRCodeException(
+ ChessQRCodeException.Type.WRITE, "write.output.qrcode.file", e.getMessage()
+ );
+ }
+ }
+
+ public void write(ChessQRCodeMode mode, String contents, ImageFormat format, OutputStream stream)
+ throws ChessQRCodeException
+ {
+ try {
+ BufferedImage image = generate(mode, contents);
+ if (!ImageIO.write(image, format.name(), stream)) {
+ throw new ChessQRCodeException(
+ ChessQRCodeException.Type.WRITE, "write.output.qrcode.stream"
+ );
+ }
+ } catch (IOException e) {
+ throw new ChessQRCodeException(
+ ChessQRCodeException.Type.WRITE, "write.output.qrcode.stream", e.getMessage()
+ );
+ }
+ }
+
+ public BufferedImage generate(ChessQRCodeMode mode, String contents)
+ throws ChessQRCodeException
+ {
+ return generate(mode, contents, DEF_QRCODE_BIT_SIZE, DEF_QRCODE_BIT_SIZE);
+ }
+
+ public BufferedImage generate(ChessQRCodeMode mode, String contents, int width, int height)
+ throws ChessQRCodeException
+ {
+ BitMatrix bitMatrix = encode(
+ mode, contents,
+ width, height,
+ null
+ );
+
+ return MatrixToImageWriter.toBufferedImage(
+ bitMatrix
+ );
+ }
+
+ private BitMatrix encode(
+ ChessQRCodeMode mode,
+ String contents,
+ int width, int height,
+ Map<EncodeHintType,?> hints)
+ throws ChessQRCodeException
+ {
+ if (mode == null) {
+ throw new ChessQRCodeException(
+ ChessQRCodeException.Type.WRITE, "write.qrcode.mode.null"
+ );
+ }
+
+ if (contents == null || contents.isEmpty()) {
+ throw new ChessQRCodeException(
+ ChessQRCodeException.Type.WRITE, "write.qrcode.contents.empty"
+ );
+ }
+
+ if (width < 0 || height < 0) { // todo
+ throw new ChessQRCodeException(
+ ChessQRCodeException.Type.WRITE, "write.qrcode.size.incorrect"
+ );
+ }
+
+ int quietZone = DEF_QUIET_ZONE_SIZE;
+ ErrorCorrectionLevel errorCorrectionLevel = DEF_ERR_CORR_LEVEL;
+
+ Map<EncodeHintType,Object> newHints = new EnumMap<>(EncodeHintType.class);
+ if (hints != null) {
+ newHints.putAll(hints);
+ if (!hints.containsKey(EncodeHintType.CHARACTER_SET)) {
+ newHints.put(EncodeHintType.CHARACTER_SET, ChessQRCodeConstants.CHARSET.name());
+ }
+ if (hints.containsKey(EncodeHintType.ERROR_CORRECTION)) {
+ errorCorrectionLevel = ErrorCorrectionLevel.valueOf(
+ hints.get(EncodeHintType.ERROR_CORRECTION).toString()
+ );
+ }
+ if (hints.containsKey(EncodeHintType.MARGIN)) {
+ quietZone = Integer.parseInt(
+ hints.get(EncodeHintType.MARGIN).toString()
+ );
+ }
+ } else {
+ newHints.put(EncodeHintType.CHARACTER_SET, ChessQRCodeConstants.CHARSET.name());
+ }
+ hints = newHints;
+
+ String qrCodeText = mode.name().concat(contents);
+
+ QRCode qrCode;
+ try {
+ qrCode = Encoder.encode(
+ qrCodeText, errorCorrectionLevel, hints
+ );
+ } catch (WriterException e) {
+ throw new ChessQRCodeException(
+ ChessQRCodeException.Type.WRITE, "write.zxing.qrcode.error", e.getMessage()
+ );
+ }
+
+ return renderMatrix(
+ qrCode, width, height, quietZone
+ );
+ }
+
+ private BitMatrix renderMatrix(QRCode qrCode, int width, int height, int quietZone)
+ throws ChessQRCodeException
+ {
+ ByteMatrix byteMatrix =
+ ChessQRMatrixUtils.embedChessLogoPattern(
+ qrCode.getMatrix()
+ );
+
+ if (byteMatrix == null) {
+ throw new ChessQRCodeException(
+ ChessQRCodeException.Type.WRITE, "write.qrcode.chess.incorrect"
+ );
+ }
+
+ return ChessQRMatrixUtils.renderMatrix(
+ byteMatrix,
+ width,
+ height,
+ quietZone
+ );
+ }
+
+ public static ChessQRCodeWriter getInstance() {
+ return _instance;
+ }
+
+
+ public static void main(String[] args) {
+ try {
+ ChessQRCodeWriter.getInstance().write(
+ ChessQRCodeMode.FEN,
+ "rnbqkbnr/ppp1pppp/8/3p4/4P3/8/PPPP1PPP/RNBQKBNR w KQkq d6 0 2",
+ ImageFormat.PNG,
+ "./MyQRCode.png"
+ );
+/*
+ ChessQRCodeWriter.getInstance().write(
+ ChessQRCodeMode.PGN,
+ "1.e4 c6 2.d4 d5 3.Nc3 dxe4 4.Nxe4 Nd7 5.Ng5 Ngf6 6.Bd3 e6 7.N1f3 h6\n" +
+ "8.Nxe6 Qe7 9.O-O fxe6 10.Bg6+ Kd8 {Каспаров встряхнул головой} \n" +
+ "11.Bf4 b5 12.a4 Bb7 13.Re1 Nd5 14.Bg3 Kc8 15.axb5 cxb5 16.Qd3 Bc6 \n" +
+ "17.Bf5 exf5 18.Rxe7 Bxe7 19.c4 1-0",
+ ImageFormat.PNG,
+ "./MyQRCode.png"
+ );
+*/
+ } catch (ChessQRCodeException e) {
+ System.out.println("Could not generate QR Code, Exception: " + e.getMessage());
+ }
+ }
+
+}