X-Git-Url: https://git.hedgecode.org/?p=chesshog.git;a=blobdiff_plain;f=chesshog-qrcode%2Fsrc%2Fmain%2Fjava%2Forg%2Fhedgecode%2Fchess%2Fqrcode%2FChessQRCodeWriter.java;fp=chesshog-qrcode%2Fsrc%2Fmain%2Fjava%2Forg%2Fhedgecode%2Fchess%2Fqrcode%2FChessQRCodeWriter.java;h=bc1175087ef43e17ca9cda13e106c3894f692256;hp=0000000000000000000000000000000000000000;hb=1fbf14530416c16f1c6fa5ee3e589482dd722a5d;hpb=4d2b7f345d8079775373d95ab7c1a486cac96519 diff --git a/chesshog-qrcode/src/main/java/org/hedgecode/chess/qrcode/ChessQRCodeWriter.java b/chesshog-qrcode/src/main/java/org/hedgecode/chess/qrcode/ChessQRCodeWriter.java new file mode 100644 index 0000000..bc11750 --- /dev/null +++ b/chesshog-qrcode/src/main/java/org/hedgecode/chess/qrcode/ChessQRCodeWriter.java @@ -0,0 +1,260 @@ +/* + * 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 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 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()); + } + } + +}