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;
21 import java.io.IOException;
22 import java.io.InputStream;
24 import java.util.EnumMap;
27 import javax.imageio.ImageIO;
29 import com.google.zxing.BinaryBitmap;
30 import com.google.zxing.DecodeHintType;
31 import com.google.zxing.ReaderException;
32 import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
33 import com.google.zxing.common.DecoderResult;
34 import com.google.zxing.common.DetectorResult;
35 import com.google.zxing.common.HybridBinarizer;
36 import com.google.zxing.qrcode.decoder.Decoder;
37 import com.google.zxing.qrcode.detector.Detector;
40 * Chess-specific QR Codes reader (image decoder).
42 * @author Dmitry Samoshin aka gotty
44 public class ChessQRCodeReader {
46 private final Decoder decoder;
48 private static ChessQRCodeReader _instance = new ChessQRCodeReader();
50 protected ChessQRCodeReader() {
51 decoder = new Decoder();
54 public ChessQRResult read(File qrCodeImageFile) throws ChessQRCodeException {
55 BufferedImage qrCodeImage;
57 qrCodeImage = ImageIO.read(qrCodeImageFile);
58 } catch (IOException e) {
59 throw new ChessQRCodeException(
60 ChessQRCodeException.Type.READ, "read.input.qrcode.file", qrCodeImageFile.getName()
63 return read(qrCodeImage);
66 public ChessQRResult read(InputStream qrCodeInputStream) throws ChessQRCodeException {
67 BufferedImage qrCodeImage;
69 qrCodeImage = ImageIO.read(qrCodeInputStream);
70 } catch (IOException e) {
71 throw new ChessQRCodeException(
72 ChessQRCodeException.Type.READ, "read.input.qrcode.stream", e.getMessage()
75 return read(qrCodeImage);
78 public ChessQRResult read(URI qrCodeUri) throws ChessQRCodeException {
79 BufferedImage qrCodeImage;
81 qrCodeImage = ImageIO.read(qrCodeUri.toURL());
82 } catch (IOException e) {
83 throw new ChessQRCodeException(
84 ChessQRCodeException.Type.READ, "read.input.qrcode.url", qrCodeUri.toASCIIString()
87 return read(qrCodeImage);
90 public ChessQRResult read(BufferedImage qrCodeImage) throws ChessQRCodeException {
91 BinaryBitmap bitmap = new BinaryBitmap(
93 new BufferedImageLuminanceSource(qrCodeImage)
96 return decode(bitmap, null);
99 private ChessQRResult decode(BinaryBitmap image, Map<DecodeHintType,?> hints)
100 throws ChessQRCodeException
102 Map<DecodeHintType,Object> newHints = new EnumMap<>(DecodeHintType.class);
104 newHints.putAll(hints);
105 if (!hints.containsKey(DecodeHintType.CHARACTER_SET))
106 newHints.put(DecodeHintType.CHARACTER_SET, ChessQRCodeConstants.CHARSET.name());
108 newHints.put(DecodeHintType.CHARACTER_SET, ChessQRCodeConstants.CHARSET.name());
112 DecoderResult decoderResult;
114 DetectorResult detectorResult = new Detector(
115 image.getBlackMatrix()
118 decoderResult = decoder.decode(
119 detectorResult.getBits(), hints
121 } catch (ReaderException e) {
122 throw new ChessQRCodeException(
123 ChessQRCodeException.Type.READ, "read.zxing.qrcode.error", e.getMessage()
127 return createResult(decoderResult);
129 ResultPoint[] points = detectorResult.getPoints();
131 if (decoderResult.getOther() instanceof QRCodeDecoderMetaData) {
132 ((QRCodeDecoderMetaData) decoderResult.getOther()).applyMirroredCorrection(points);
135 Result result = new Result(
136 decoderResult.getText(),
137 decoderResult.getRawBytes(),
139 BarcodeFormat.QR_CODE
142 List<byte[]> byteSegments = decoderResult.getByteSegments();
143 if (byteSegments != null) {
144 result.putMetadata(ResultMetadataType.BYTE_SEGMENTS, byteSegments);
146 String ecLevel = decoderResult.getECLevel();
147 if (ecLevel != null) {
148 result.putMetadata(ResultMetadataType.ERROR_CORRECTION_LEVEL, ecLevel);
150 if (decoderResult.hasStructuredAppend()) {
152 ResultMetadataType.STRUCTURED_APPEND_SEQUENCE,
153 decoderResult.getStructuredAppendSequenceNumber()
156 ResultMetadataType.STRUCTURED_APPEND_PARITY,
157 decoderResult.getStructuredAppendParity()
164 protected ChessQRResult createResult(DecoderResult decoderResult) throws ChessQRCodeException {
165 String result = decoderResult.getText();
167 ChessQRCodeMode mode = ChessQRResult.getMode(result);
169 throw new ChessQRCodeException(
170 ChessQRCodeException.Type.READ, "read.unknown.chess.mode"
174 return new ChessQRResult(
176 ChessQRResult.getContents(result)
180 public static ChessQRCodeReader getInstance() {
185 public static void main(String[] args) {
187 ChessQRResult qrCodeResult = ChessQRCodeReader.getInstance().read(
188 new File("qrcode.png")
190 System.out.println("Decoded format = " + qrCodeResult.getMode());
191 System.out.println("Decoded text = " + qrCodeResult.getContents());
192 } catch (ChessQRCodeException e) {
193 System.out.println("Could not decode QR Code. Exception: " + e.getMessage());