ce82e11a126e10b9c6da3d05c9fe2e9829dcdb5f
[zxing.git] / cpp / magick / src / main.cpp
1 /*
2  *  main.cpp
3  *  zxing
4  *
5  *  Created by Ralf Kistner on 16/10/2009.
6  *  Copyright 2008 ZXing authors All rights reserved.
7  *
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
11  *
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  *
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.
19  */
20
21 #include <iostream>
22 #include <fstream>
23 #include <string>
24 #include <Magick++.h>
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>
32 #include <exception>
33 #include <zxing/Exception.h>
34 #include <zxing/common/IllegalArgumentException.h>
35 #include <zxing/BinaryBitmap.h>
36
37 #include <zxing/qrcode/detector/Detector.h>
38 #include <zxing/qrcode/detector/QREdgeDetector.h>
39 #include <zxing/qrcode/decoder/Decoder.h>
40
41 using namespace Magick;
42 using namespace std;
43 using namespace zxing;
44 using namespace zxing::qrcode;
45
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);
51
52   PixelPacket* pixels = image.getPixels(0, 0, width, height);
53
54   PixelPacket* pixel = pixels;
55   ColorMono color;
56   for (int y = 0; y < height; y++) {
57     for (int x = 0; x < width; x++) {
58       color.mono(!matrix->get(x, y));
59       *pixel = color;
60       pixel++;
61     }
62   }
63   image.syncPixels();
64 }
65
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);
73 }
74
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));
77
78   draw_matrix(image, matrix);
79
80   image.strokeColor(Color(MaxRGB, 0, 0, MaxRGB / 3));
81   image.fillColor(Color(0, 0, 0, MaxRGB));
82   image.strokeWidth(1);
83
84   for (int i = 0; i <= dimension; i++) {
85     valarray<float> tpoints(0.0, 4);
86
87     tpoints[0] = 0;
88     tpoints[1] = i;
89     tpoints[2] = dimension;
90     tpoints[3] = i;
91     transform->transformPoints(tpoints);
92
93     DrawableLine line1(tpoints[0], tpoints[1], tpoints[2], tpoints[3]);
94     image.draw(line1);
95
96     tpoints[0] = i;
97     tpoints[1] = 0;
98     tpoints[2] = i;
99     tpoints[3] = dimension;
100     transform->transformPoints(tpoints);
101
102     DrawableLine line2(tpoints[0], tpoints[1], tpoints[2], tpoints[3]);
103     image.draw(line2);
104   }
105
106   image.write(filename);
107 }
108
109 Ref<Result> decode(string out_prefix, Ref<BinaryBitmap> image, string& cell_grid, string& cell_transformed) {
110   Decoder decoder;
111
112   QREdgeDetector detector = QREdgeDetector(image->getBlackMatrix());
113
114   Ref<DetectorResult> detectorResult(detector.detect());
115
116   if (out_prefix.size()) {
117     // Grid image
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 + "\" />";
123
124     // Transformed image
125     string tfile = out_prefix + ".transformed.png";
126     save_matrix(detectorResult->getBits(), tfile, 5);
127     cell_transformed = "<img src=\"" + tfile + "\" />";
128   }
129
130
131   vector<Ref<ResultPoint> > points(detectorResult->getPoints());
132
133   Ref<DecoderResult> decoderResult(decoder.decode(detectorResult->getBits()));
134
135   Ref<Result> result(new Result(decoderResult->getText(),
136                                 decoderResult->getRawBytes(),
137                                 points,
138                                 BarcodeFormat_QR_CODE));
139
140   return result;
141 }
142
143
144
145
146 int test_image(Image& image, string out_prefix, bool localized) {
147   string cell_mono;
148   string cell_transformed;
149   string cell_result;
150   string cell_grid;
151   string result_color = "red";
152   int res = -1;
153
154   Ref<BitMatrix> matrix(NULL);
155   Ref<Binarizer> binarizer(NULL);
156
157
158   try {
159     Ref<MagickBitmapSource> source(new MagickBitmapSource(image));
160
161     if (localized) {
162       binarizer = new LocalBlockBinarizer(source);
163     } else {
164       binarizer = new GlobalHistogramBinarizer(source);
165     }
166
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 + "\" />";
172     }
173
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";
178     res = 0;
179   } catch (ReaderException e) {
180     cell_result = "zxing::ReaderException: " + string(e.what());
181     res = -2;
182   } catch (zxing::IllegalArgumentException& e) {
183     cell_result = "zxing::IllegalArgumentException: " + string(e.what());
184     res = -3;
185   } catch (zxing::Exception& e) {
186     cell_result = "zxing::Exception: " + string(e.what());
187     res = -4;
188   } catch (std::exception& e) {
189     cell_result = "std::exception: " + string(e.what());
190     res = -5;
191   }
192
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;
197   return res;
198 }
199
200 int test_image_local(Image& image, string out_prefix) {
201   return test_image(image, out_prefix, true);
202 }
203
204 int test_image_global(Image& image, string out_prefix) {
205   return test_image(image, out_prefix, false);
206 }
207
208
209 int main(int argc, char** argv) {
210   if (argc <= 2) {
211     cout << "Usage: " << argv[0] << " [<outfolder> | \"-\"] <filename1> [<filename2> ...]" << endl;
212     return 1;
213   }
214   string outfolder = argv[1];
215
216   int total = argc - 2;
217   int gonly = 0;
218   int lonly = 0;
219   int both = 0;
220   int neither = 0;
221
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;
226     Image image;
227     try {
228       image.read(infilename);
229     } catch (...) {
230       cerr << "Unable to open image, ignoring" << endl;
231       continue;
232     }
233     cout << "<tr><td colspan=\"5\">" << infilename << "</td></tr>" << endl;
234     cout << "<tr>" << endl;
235
236     cout << "<td><img src=\"" << infilename << "\" /></td>" << endl;
237
238
239     int gresult = 1;
240     int lresult = 1;
241
242     if (outfolder == string("-")) {
243       gresult = test_image_global(image, "");
244       lresult = test_image_local(image, "");
245     } else {
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");
250     }
251
252     gresult = gresult == 0;
253     lresult = lresult == 0;
254
255     gonly += gresult && !lresult;
256     lonly += lresult && !gresult;
257     both += gresult && lresult;
258     neither += !gresult && !lresult;
259
260     cout << "</tr>" << endl;
261   }
262   cout << "</table>" << endl;
263
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;
270
271   cout << "</table>" << endl;
272   cout << "</body></html>" << endl;
273
274   return 0;
275 }
276
277