5 * Created by Ralf Kistner on 16/10/2009.
6 * Copyright 2008 ZXing authors All rights reserved.
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
25 #include "MagickBitmapSource.h"
26 #include <zxing/common/Counted.h>
27 #include <zxing/qrcode/QRCodeReader.h>
28 #include <zxing/Result.h>
29 #include <zxing/ReaderException.h>
30 #include <zxing/common/GlobalHistogramBinarizer.h>
31 #include <zxing/common/LocalBlockBinarizer.h>
33 #include <zxing/Exception.h>
34 #include <zxing/common/IllegalArgumentException.h>
35 #include <zxing/BinaryBitmap.h>
37 #include <zxing/qrcode/detector/Detector.h>
38 #include <zxing/qrcode/detector/QREdgeDetector.h>
39 #include <zxing/qrcode/decoder/Decoder.h>
41 using namespace Magick;
43 using namespace zxing;
44 using namespace zxing::qrcode;
46 void draw_matrix(Image& image, Ref<BitMatrix> matrix) {
47 int width = matrix->getWidth();
48 int height = matrix->getHeight();
49 // image.modifyImage();
50 // image.type(TrueColorType);
52 PixelPacket* pixels = image.getPixels(0, 0, width, height);
54 PixelPacket* pixel = pixels;
56 for (int y = 0; y < height; y++) {
57 for (int x = 0; x < width; x++) {
58 color.mono(!matrix->get(x, y));
66 void save_matrix(Ref<BitMatrix> matrix, string filename, float scale = 1.0) {
67 Image image(Geometry(matrix->getWidth(), matrix->getHeight()), Color(MaxRGB, MaxRGB, MaxRGB, 0));
68 int width = matrix->getWidth();
69 int height = matrix->getHeight();
70 draw_matrix(image, matrix);
71 image.scale(Geometry(width*scale, height*scale));
72 image.write(filename);
75 void save_grid(Ref<BitMatrix> matrix, string filename, Ref<PerspectiveTransform> transform, int dimension) {
76 Image image(Geometry(matrix->getWidth(), matrix->getHeight()), Color(MaxRGB, MaxRGB, MaxRGB, 0));
78 draw_matrix(image, matrix);
80 image.strokeColor(Color(MaxRGB, 0, 0, MaxRGB / 3));
81 image.fillColor(Color(0, 0, 0, MaxRGB));
84 for (int i = 0; i <= dimension; i++) {
85 valarray<float> tpoints(0.0, 4);
89 tpoints[2] = dimension;
91 transform->transformPoints(tpoints);
93 DrawableLine line1(tpoints[0], tpoints[1], tpoints[2], tpoints[3]);
99 tpoints[3] = dimension;
100 transform->transformPoints(tpoints);
102 DrawableLine line2(tpoints[0], tpoints[1], tpoints[2], tpoints[3]);
106 image.write(filename);
109 Ref<Result> decode(string out_prefix, Ref<BinaryBitmap> image, string& cell_grid, string& cell_transformed) {
112 QREdgeDetector detector = QREdgeDetector(image->getBlackMatrix());
114 Ref<DetectorResult> detectorResult(detector.detect());
116 if (out_prefix.size()) {
118 string gridfile = out_prefix + ".grid.gif";
119 Ref<PerspectiveTransform> transform = detectorResult->getTransform();
120 int dimension = detectorResult->getBits()->getDimension();
121 save_grid(image->getBlackMatrix(), gridfile, transform, dimension);
122 cell_grid = "<img src=\"" + gridfile + "\" />";
125 string tfile = out_prefix + ".transformed.png";
126 save_matrix(detectorResult->getBits(), tfile, 5);
127 cell_transformed = "<img src=\"" + tfile + "\" />";
131 vector<Ref<ResultPoint> > points(detectorResult->getPoints());
133 Ref<DecoderResult> decoderResult(decoder.decode(detectorResult->getBits()));
135 Ref<Result> result(new Result(decoderResult->getText(),
136 decoderResult->getRawBytes(),
138 BarcodeFormat_QR_CODE));
146 int test_image(Image& image, string out_prefix, bool localized) {
148 string cell_transformed;
151 string result_color = "red";
154 Ref<BitMatrix> matrix(NULL);
155 Ref<Binarizer> binarizer(NULL);
159 Ref<MagickBitmapSource> source(new MagickBitmapSource(image));
162 binarizer = new LocalBlockBinarizer(source);
164 binarizer = new GlobalHistogramBinarizer(source);
167 if (out_prefix.size()) {
168 string monofile = out_prefix + ".mono.png";
169 matrix = binarizer->getBlackMatrix();
170 save_matrix(matrix, monofile);
171 cell_mono = "<img src=\"" + monofile + "\" />";
174 Ref<BinaryBitmap> binary(new BinaryBitmap(binarizer));
175 Ref<Result> result(decode(out_prefix, binary, cell_grid, cell_transformed));
176 cell_result = result->getText()->getText();
177 result_color = "green";
179 } catch (ReaderException e) {
180 cell_result = "zxing::ReaderException: " + string(e.what());
182 } catch (zxing::IllegalArgumentException& e) {
183 cell_result = "zxing::IllegalArgumentException: " + string(e.what());
185 } catch (zxing::Exception& e) {
186 cell_result = "zxing::Exception: " + string(e.what());
188 } catch (std::exception& e) {
189 cell_result = "std::exception: " + string(e.what());
193 cout << "<td>" << cell_mono << "</td>" << endl;
194 cout << "<td>" << cell_grid << "</td>" << endl;
195 cout << "<td>" << cell_transformed << "</td>" << endl;
196 cout << "<td bgcolor=\"" << result_color << "\">" << cell_result << "</td>" << endl;
200 int test_image_local(Image& image, string out_prefix) {
201 return test_image(image, out_prefix, true);
204 int test_image_global(Image& image, string out_prefix) {
205 return test_image(image, out_prefix, false);
209 int main(int argc, char** argv) {
211 cout << "Usage: " << argv[0] << " [<outfolder> | \"-\"] <filename1> [<filename2> ...]" << endl;
214 string outfolder = argv[1];
216 int total = argc - 2;
222 cout << "<html><body><table border=\"1\">" << endl;
223 for (int i = 2; i < argc; i++) {
224 string infilename = argv[i];
225 cerr << "Processing: " << infilename << endl;
228 image.read(infilename);
230 cerr << "Unable to open image, ignoring" << endl;
233 cout << "<tr><td colspan=\"5\">" << infilename << "</td></tr>" << endl;
234 cout << "<tr>" << endl;
236 cout << "<td><img src=\"" << infilename << "\" /></td>" << endl;
242 if (outfolder == string("-")) {
243 gresult = test_image_global(image, "");
244 lresult = test_image_local(image, "");
246 replace(infilename.begin(), infilename.end(), '/', '_');
247 string prefix = string(outfolder) + string("/") + infilename;
248 gresult = test_image_global(image, prefix + ".g");
249 lresult = test_image_local(image, prefix + ".l");
252 gresult = gresult == 0;
253 lresult = lresult == 0;
255 gonly += gresult && !lresult;
256 lonly += lresult && !gresult;
257 both += gresult && lresult;
258 neither += !gresult && !lresult;
260 cout << "</tr>" << endl;
262 cout << "</table>" << endl;
264 cout << "<table>" << endl;
265 cout << "<tr><td>Total</td><td>" << total << "</td></tr>" << endl;
266 cout << "<tr><td>Both correct</td><td>" << both << "</td></tr>" << endl;
267 cout << "<tr><td>Neither correct</td><td>" << neither << "</td></tr>" << endl;
268 cout << "<tr><td>Global only</td><td>" << gonly << "</td></tr>" << endl;
269 cout << "<tr><td>Local only</td><td>" << lonly << "</td></tr>" << endl;
271 cout << "</table>" << endl;
272 cout << "</body></html>" << endl;