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;
39 import org.hedgecode.chess.ChessQRCodeConstants;
42 * Chess-specific QR Codes reader (image decoder).
44 * @author Dmitry Samoshin aka gotty
46 public class ChessQRCodeReader {
48 private final Decoder decoder;
50 private static ChessQRCodeReader _instance = new ChessQRCodeReader();
52 private ChessQRCodeReader() {
53 decoder = new Decoder();
56 public ChessQRResult read(File qrCodeImageFile) throws ChessQRCodeException {
57 BufferedImage qrCodeImage;
59 qrCodeImage = ImageIO.read(qrCodeImageFile);
60 } catch (IOException e) {
61 throw new ChessQRCodeException(
62 ChessQRCodeException.Type.READ, "read.input.qrcode.file", qrCodeImageFile.getName()
65 return read(qrCodeImage);
68 public ChessQRResult read(InputStream qrCodeInputStream) throws ChessQRCodeException {
69 BufferedImage qrCodeImage;
71 qrCodeImage = ImageIO.read(qrCodeInputStream);
72 } catch (IOException e) {
73 throw new ChessQRCodeException(
74 ChessQRCodeException.Type.READ, "read.input.qrcode.stream", e.getMessage()
77 return read(qrCodeImage);
80 public ChessQRResult read(URI qrCodeUri) throws ChessQRCodeException {
81 BufferedImage qrCodeImage;
83 qrCodeImage = ImageIO.read(qrCodeUri.toURL());
84 } catch (IOException e) {
85 throw new ChessQRCodeException(
86 ChessQRCodeException.Type.READ, "read.input.qrcode.url", qrCodeUri.toASCIIString()
89 return read(qrCodeImage);
92 public ChessQRResult read(BufferedImage qrCodeImage) throws ChessQRCodeException {
93 BinaryBitmap bitmap = new BinaryBitmap(
95 new BufferedImageLuminanceSource(qrCodeImage)
98 return decode(bitmap, null);
101 private ChessQRResult decode(BinaryBitmap image, Map<DecodeHintType,?> hints)
102 throws ChessQRCodeException
104 Map<DecodeHintType,Object> newHints = new EnumMap<>(DecodeHintType.class);
106 newHints.putAll(hints);
107 if (!hints.containsKey(DecodeHintType.CHARACTER_SET))
108 newHints.put(DecodeHintType.CHARACTER_SET, ChessQRCodeConstants.CHARSET.name());
110 newHints.put(DecodeHintType.CHARACTER_SET, ChessQRCodeConstants.CHARSET.name());
114 DecoderResult decoderResult;
116 DetectorResult detectorResult = new Detector(
117 image.getBlackMatrix()
120 decoderResult = decoder.decode(
121 detectorResult.getBits(), hints
123 } catch (ReaderException e) {
124 throw new ChessQRCodeException(
125 ChessQRCodeException.Type.READ, "read.zxing.qrcode.error", e.getMessage()
129 ChessQRCodeMode mode = ChessQRCodeMode.byCode(
130 decoderResult.getText().substring(0, ChessQRCodeMode.CODE_LENGTH)
134 throw new ChessQRCodeException(
135 ChessQRCodeException.Type.READ, "read.unknown.chess.mode"
139 return new ChessQRResult(
141 decoderResult.getText().substring(ChessQRCodeMode.CODE_LENGTH)
144 ResultPoint[] points = detectorResult.getPoints();
146 if (decoderResult.getOther() instanceof QRCodeDecoderMetaData) {
147 ((QRCodeDecoderMetaData) decoderResult.getOther()).applyMirroredCorrection(points);
150 Result result = new Result(
151 decoderResult.getText(),
152 decoderResult.getRawBytes(),
154 BarcodeFormat.QR_CODE
157 List<byte[]> byteSegments = decoderResult.getByteSegments();
158 if (byteSegments != null) {
159 result.putMetadata(ResultMetadataType.BYTE_SEGMENTS, byteSegments);
161 String ecLevel = decoderResult.getECLevel();
162 if (ecLevel != null) {
163 result.putMetadata(ResultMetadataType.ERROR_CORRECTION_LEVEL, ecLevel);
165 if (decoderResult.hasStructuredAppend()) {
167 ResultMetadataType.STRUCTURED_APPEND_SEQUENCE,
168 decoderResult.getStructuredAppendSequenceNumber()
171 ResultMetadataType.STRUCTURED_APPEND_PARITY,
172 decoderResult.getStructuredAppendParity()
179 public static ChessQRCodeReader getInstance() {
184 public static void main(String[] args) {
186 ChessQRResult qrCodeResult = ChessQRCodeReader.getInstance().read(
187 new File("MyQRCode.png")
189 System.out.println("Decoded format = " + qrCodeResult.getMode());
190 System.out.println("Decoded text = " + qrCodeResult.getContents());
191 } catch (ChessQRCodeException e) {
192 System.out.println("Could not decode QR Code. Exception: " + e.getMessage());