* main.cpp
* zxing
*
- * Created by Ralf Kistner on 16/10/2009.
- * Copyright 2008 ZXing authors All rights reserved.
+ * Copyright 2010 ZXing authors All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
#include <Magick++.h>
#include "MagickBitmapSource.h"
#include <zxing/common/Counted.h>
-#include <zxing/qrcode/QRCodeReader.h>
+//#include <zxing/qrcode/QRCodeReader.h>
+#include <zxing/Binarizer.h>
+#include <zxing/MultiFormatReader.h>
#include <zxing/Result.h>
#include <zxing/ReaderException.h>
#include <zxing/common/GlobalHistogramBinarizer.h>
-#include <zxing/common/LocalBlockBinarizer.h>
+#include <zxing/common/HybridBinarizer.h>
#include <exception>
#include <zxing/Exception.h>
#include <zxing/common/IllegalArgumentException.h>
#include <zxing/BinaryBitmap.h>
+#include <zxing/DecodeHints.h>
-#include <zxing/qrcode/detector/Detector.h>
-#include <zxing/qrcode/detector/QREdgeDetector.h>
-#include <zxing/qrcode/decoder/Decoder.h>
+//#include <zxing/qrcode/detector/Detector.h>
+//#include <zxing/qrcode/detector/QREdgeDetector.h>
+//#include <zxing/qrcode/decoder/Decoder.h>
using namespace Magick;
using namespace std;
using namespace zxing;
-using namespace zxing::qrcode;
-
-void draw_matrix(Image& image, Ref<BitMatrix> matrix) {
- int width = matrix->getWidth();
- int height = matrix->getHeight();
-// image.modifyImage();
-// image.type(TrueColorType);
-
- PixelPacket* pixels = image.getPixels(0, 0, width, height);
-
- PixelPacket* pixel = pixels;
- ColorMono color;
- for (int y = 0; y < height; y++) {
- for (int x = 0; x < width; x++) {
- color.mono(!matrix->get(x, y));
- *pixel = color;
- pixel++;
- }
- }
- image.syncPixels();
-}
-
-void save_matrix(Ref<BitMatrix> matrix, string filename, float scale = 1.0) {
- Image image(Geometry(matrix->getWidth(), matrix->getHeight()), Color(MaxRGB, MaxRGB, MaxRGB, 0));
- int width = matrix->getWidth();
- int height = matrix->getHeight();
- draw_matrix(image, matrix);
- image.scale(Geometry(width*scale, height*scale));
- image.write(filename);
-}
-
-void save_grid(Ref<BitMatrix> matrix, string filename, Ref<PerspectiveTransform> transform, int dimension) {
- Image image(Geometry(matrix->getWidth(), matrix->getHeight()), Color(MaxRGB, MaxRGB, MaxRGB, 0));
-
- draw_matrix(image, matrix);
-
- image.strokeColor(Color(MaxRGB, 0, 0, MaxRGB / 3));
- image.fillColor(Color(0, 0, 0, MaxRGB));
- image.strokeWidth(1);
-
- for (int i = 0; i <= dimension; i++) {
- valarray<float> tpoints(0.0, 4);
-
- tpoints[0] = 0;
- tpoints[1] = i;
- tpoints[2] = dimension;
- tpoints[3] = i;
- transform->transformPoints(tpoints);
-
- DrawableLine line1(tpoints[0], tpoints[1], tpoints[2], tpoints[3]);
- image.draw(line1);
-
- tpoints[0] = i;
- tpoints[1] = 0;
- tpoints[2] = i;
- tpoints[3] = dimension;
- transform->transformPoints(tpoints);
-
- DrawableLine line2(tpoints[0], tpoints[1], tpoints[2], tpoints[3]);
- image.draw(line2);
- }
+//using namespace zxing::qrcode;
- image.write(filename);
-}
-
-Ref<Result> decode(string out_prefix, Ref<BinaryBitmap> image, string& cell_grid, string& cell_transformed) {
- Decoder decoder;
-
- QREdgeDetector detector = QREdgeDetector(image->getBlackMatrix());
-
- Ref<DetectorResult> detectorResult(detector.detect());
-
- if (out_prefix.size()) {
- // Grid image
- string gridfile = out_prefix + ".grid.gif";
- Ref<PerspectiveTransform> transform = detectorResult->getTransform();
- int dimension = detectorResult->getBits()->getDimension();
- save_grid(image->getBlackMatrix(), gridfile, transform, dimension);
- cell_grid = "<img src=\"" + gridfile + "\" />";
-
- // Transformed image
- string tfile = out_prefix + ".transformed.png";
- save_matrix(detectorResult->getBits(), tfile, 5);
- cell_transformed = "<img src=\"" + tfile + "\" />";
- }
+static bool raw_dump = false;
+static bool show_format = false;
+static bool tryHarder = false;
+static bool show_filename = false;
+static const int MAX_EXPECTED = 1024;
- vector<Ref<ResultPoint> > points(detectorResult->getPoints());
-
- Ref<DecoderResult> decoderResult(decoder.decode(detectorResult->getBits()));
-
- Ref<Result> result(new Result(decoderResult->getText(),
- decoderResult->getRawBytes(),
- points,
- BarcodeFormat_QR_CODE));
-
- return result;
+Ref<Result> decode(Ref<BinaryBitmap> image, DecodeHints hints) {
+ Ref<Reader> reader(new MultiFormatReader);
+ return Ref<Result> (new Result(*reader->decode(image, hints)));
}
+int test_image(Image& image, bool hybrid, string expected = "") {
-
-int test_image(Image& image, string out_prefix, bool localized) {
- string cell_mono;
- string cell_transformed;
string cell_result;
- string cell_grid;
- string result_color = "red";
int res = -1;
Ref<BitMatrix> matrix(NULL);
Ref<Binarizer> binarizer(NULL);
-
+ const char* result_format = "";
try {
Ref<MagickBitmapSource> source(new MagickBitmapSource(image));
- if (localized) {
- binarizer = new LocalBlockBinarizer(source);
+ if (hybrid) {
+ binarizer = new HybridBinarizer(source);
} else {
binarizer = new GlobalHistogramBinarizer(source);
}
- if (out_prefix.size()) {
- string monofile = out_prefix + ".mono.png";
- matrix = binarizer->getBlackMatrix();
- save_matrix(matrix, monofile);
- cell_mono = "<img src=\"" + monofile + "\" />";
- }
-
+ DecodeHints hints(DecodeHints::DEFAULT_HINT);
+ hints.setTryHarder(tryHarder);
Ref<BinaryBitmap> binary(new BinaryBitmap(binarizer));
- Ref<Result> result(decode(out_prefix, binary, cell_grid, cell_transformed));
+ Ref<Result> result(decode(binary, hints));
cell_result = result->getText()->getText();
- result_color = "green";
+ result_format = barcodeFormatNames[result->getBarcodeFormat()];
res = 0;
} catch (ReaderException e) {
cell_result = "zxing::ReaderException: " + string(e.what());
res = -5;
}
- cout << "<td>" << cell_mono << "</td>" << endl;
- cout << "<td>" << cell_grid << "</td>" << endl;
- cout << "<td>" << cell_transformed << "</td>" << endl;
- cout << "<td bgcolor=\"" << result_color << "\">" << cell_result << "</td>" << endl;
+ if (cell_result.compare(expected)) {
+ res = -6;
+ if (!raw_dump) {
+ cout << (hybrid ? "Hybrid" : "Global") << " binarizer failed:\n";
+ if (expected.length() >= 0) {
+ cout << " Expected: " << expected << "\n";
+ }
+ cout << " Detected: " << cell_result << endl;
+ }
+ }
+
+
+ if (raw_dump && !hybrid) {/* don't print twice, and global is a bit better */
+ cout << cell_result;
+ if (show_format) {
+ cout << " " << result_format;
+ }
+ cout << endl;
+
+ }
return res;
}
-int test_image_local(Image& image, string out_prefix) {
- return test_image(image, out_prefix, true);
+int test_image_hybrid(Image& image, string expected = "") {
+ return test_image(image, true, expected);
}
-int test_image_global(Image& image, string out_prefix) {
- return test_image(image, out_prefix, false);
+int test_image_global(Image& image, string expected = "") {
+ return test_image(image, false, expected);
}
+string get_expected(string imagefilename) {
+ string textfilename = imagefilename;
+ int dotpos = textfilename.rfind(".");
+ textfilename.replace(dotpos+1, textfilename.length() - dotpos - 1, "txt");
+ char data[MAX_EXPECTED];
+ FILE *fp = fopen(textfilename.data(), "rb");
+
+ if (!fp) {
+ // could not open file
+ return "";
+ }
+ // get file size
+ fseek(fp, 0, SEEK_END);
+ int toread = ftell(fp);
+ rewind(fp);
+
+ if (toread > MAX_EXPECTED) {
+ cerr << "MAX_EXPECTED = " << MAX_EXPECTED << " but file '" << textfilename << "' has " << toread
+ << " bytes! Skipping..." << endl;
+ fclose(fp);
+ return "";
+ }
+
+ int nread = fread(data, sizeof(char), toread, fp);
+ if (nread != toread) {
+ cerr << "Could not read entire contents of file '" << textfilename << "'! Skipping..." << endl;
+ fclose(fp);
+ return "";
+ }
+ fclose(fp);
+ data[nread] = '\0';
+ string expected(data);
+ return expected;
+}
int main(int argc, char** argv) {
- if (argc <= 2) {
- cout << "Usage: " << argv[0] << " [<outfolder> | \"-\"] <filename1> [<filename2> ...]" << endl;
+ if (argc <= 1) {
+ cout << "Usage: " << argv[0] << " [--dump-raw] [--show-format] [--try-harder] [--show-filename] <filename1> [<filename2> ...]" << endl;
return 1;
}
- string outfolder = argv[1];
- int total = argc - 2;
+ int total = 0;
int gonly = 0;
- int lonly = 0;
+ int honly = 0;
int both = 0;
int neither = 0;
- cout << "<html><body><table border=\"1\">" << endl;
- for (int i = 2; i < argc; i++) {
+ if (argc == 2) raw_dump = true;
+
+ for (int i = 1; i < argc; i++) {
string infilename = argv[i];
- cerr << "Processing: " << infilename << endl;
+ if (infilename.substr(infilename.length()-3,3).compare("txt") == 0) {
+ continue;
+ }
+ if (infilename.compare("--dump-raw") == 0) {
+ raw_dump = true;
+ continue;
+ }
+ if (infilename.compare("--show-format") == 0) {
+ show_format = true;
+ continue;
+ }
+ if (infilename.compare("--try-harder") == 0) {
+ tryHarder = true;
+ continue;
+ }
+ if (infilename.compare("--show-filename") == 0) {
+ show_filename = true;
+ continue;
+ }
+ if (!raw_dump)
+ cerr << "Processing: " << infilename << endl;
+ if (show_filename)
+ cout << infilename << " ";
Image image;
try {
image.read(infilename);
cerr << "Unable to open image, ignoring" << endl;
continue;
}
- cout << "<tr><td colspan=\"5\">" << infilename << "</td></tr>" << endl;
- cout << "<tr>" << endl;
-
- cout << "<td><img src=\"" << infilename << "\" /></td>" << endl;
+ string expected;
+ expected = get_expected(infilename);
int gresult = 1;
- int lresult = 1;
+ int hresult = 1;
- if (outfolder == string("-")) {
- gresult = test_image_global(image, "");
- lresult = test_image_local(image, "");
- } else {
- replace(infilename.begin(), infilename.end(), '/', '_');
- string prefix = string(outfolder) + string("/") + infilename;
- gresult = test_image_global(image, prefix + ".g");
- lresult = test_image_local(image, prefix + ".l");
- }
+ hresult = test_image_hybrid(image, expected);
+ gresult = test_image_global(image, expected);
gresult = gresult == 0;
- lresult = lresult == 0;
-
- gonly += gresult && !lresult;
- lonly += lresult && !gresult;
- both += gresult && lresult;
- neither += !gresult && !lresult;
+ hresult = hresult == 0;
- cout << "</tr>" << endl;
+ gonly += gresult && !hresult;
+ honly += hresult && !gresult;
+ both += gresult && hresult;
+ neither += !gresult && !hresult;
+ total = total + 1;
}
- cout << "</table>" << endl;
-
- cout << "<table>" << endl;
- cout << "<tr><td>Total</td><td>" << total << "</td></tr>" << endl;
- cout << "<tr><td>Both correct</td><td>" << both << "</td></tr>" << endl;
- cout << "<tr><td>Neither correct</td><td>" << neither << "</td></tr>" << endl;
- cout << "<tr><td>Global only</td><td>" << gonly << "</td></tr>" << endl;
- cout << "<tr><td>Local only</td><td>" << lonly << "</td></tr>" << endl;
- cout << "</table>" << endl;
- cout << "</body></html>" << endl;
+ if (!raw_dump)
+ cout << (honly+both) << " passed hybrid, " << (gonly+both) << " passed global, "
+ << both << " pass both, " << neither << " pass neither, " << honly
+ << " passed only hybrid, " << gonly << " passed only global, of " << total
+ << " total." << endl;
return 0;
}