// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-
/*
* Copyright 2010-2011 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <iostream>
#include <fstream>
#include <string>
#include "ImageReaderSource.h"
#include <zxing/common/Counted.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/HybridBinarizer.h>
#include <exception>
#include <zxing/Exception.h>
#include <zxing/common/IllegalArgumentException.h>
#include <zxing/BinaryBitmap.h>
#include <zxing/DecodeHints.h>
#include <zxing/qrcode/QRCodeReader.h>
#include <zxing/multi/qrcode/QRCodeMultiReader.h>
#include <zxing/multi/ByQuadrantReader.h>
#include <zxing/multi/MultipleBarcodeReader.h>
#include <zxing/multi/GenericMultipleBarcodeReader.h>
using namespace std;
using namespace zxing;
using namespace zxing::multi;
using namespace zxing::qrcode;
namespace {
bool more = false;
bool test_mode = false;
bool try_harder = false;
bool search_multi = false;
bool use_hybrid = false;
bool use_global = false;
bool verbose = false;
}
vector<Ref<Result> > decode(Ref<BinaryBitmap> image, DecodeHints hints) {
Ref<Reader> reader(new MultiFormatReader);
return vector<Ref<Result> >(1, reader->decode(image, hints));
}
vector<Ref<Result> > decode_multi(Ref<BinaryBitmap> image, DecodeHints hints) {
MultiFormatReader delegate;
GenericMultipleBarcodeReader reader(delegate);
return reader.decodeMultiple(image, hints);
}
int read_image(Ref<LuminanceSource> source, bool hybrid, string expected) {
vector<Ref<Result> > results;
string cell_result;
int res = -1;
try {
Ref<Binarizer> binarizer;
if (hybrid) {
binarizer = new HybridBinarizer(source);
} else {
binarizer = new GlobalHistogramBinarizer(source);
}
DecodeHints hints(DecodeHints::DEFAULT_HINT);
hints.setTryHarder(try_harder);
Ref<BinaryBitmap> binary(new BinaryBitmap(binarizer));
if (search_multi) {
results = decode_multi(binary, hints);
} else {
results = decode(binary, hints);
}
res = 0;
} catch (const ReaderException& e) {
cell_result = "zxing::ReaderException: " + string(e.what());
res = -2;
} catch (const zxing::IllegalArgumentException& e) {
cell_result = "zxing::IllegalArgumentException: " + string(e.what());
res = -3;
} catch (const zxing::Exception& e) {
cell_result = "zxing::Exception: " + string(e.what());
res = -4;
} catch (const std::exception& e) {
cell_result = "std::exception: " + string(e.what());
res = -5;
}
if (test_mode && results.size() == 1) {
std::string result = results[0]->getText()->getText();
if (expected.empty()) {
cout << " Expected text or binary data for image missing." << endl
<< " Detected: " << result << endl;
res = -6;
} else {
if (expected.compare(result) != 0) {
cout << " Expected: " << expected << endl
<< " Detected: " << result << endl;
cell_result = "data did not match";
res = -6;
}
}
}
if (res != 0 && (verbose || (use_global ^ use_hybrid))) {
cout << (hybrid ? "Hybrid" : "Global")
<< " binarizer failed: " << cell_result << endl;
} else if (!test_mode) {
if (verbose) {
cout << (hybrid ? "Hybrid" : "Global")
<< " binarizer succeeded: " << endl;
}
for (size_t i = 0; i < results.size(); i++) {
if (more) {
cout << " Format: "
<< BarcodeFormat::barcodeFormatNames[results[i]->getBarcodeFormat()]
<< endl;
for (int j = 0; j < results[i]->getResultPoints()->size(); j++) {
cout << " Point[" << j << "]: "
<< results[i]->getResultPoints()[j]->getX() << " "
<< results[i]->getResultPoints()[j]->getY() << endl;
}
}
if (verbose) {
cout << " ";
}
cout << results[i]->getText()->getText() << endl;
}
}
return res;
}
string read_expected(string imagefilename) {
string textfilename = imagefilename;
string::size_type dotpos = textfilename.rfind(".");
textfilename.replace(dotpos + 1, textfilename.length() - dotpos - 1, "txt");
ifstream textfile(textfilename.c_str(), ios::binary);
textfilename.replace(dotpos + 1, textfilename.length() - dotpos - 1, "bin");
ifstream binfile(textfilename.c_str(), ios::binary);
ifstream *file = 0;
if (textfile.is_open()) {
file = &textfile;
} else if (binfile.is_open()) {
file = &binfile;
} else {
return std::string();
}
file->seekg(0, ios_base::end);
size_t size = size_t(file->tellg());
file->seekg(0, ios_base::beg);
if (size == 0) {
return std::string();
}
char* data = new char[size + 1];
file->read(data, size);
data[size] = '\0';
string expected(data);
delete[] data;
return expected;
}
int main(int argc, char** argv) {
if (argc <= 1) {
cout << "Usage: " << argv[0] << " [OPTION]... <IMAGE>..." << endl
<< "Read barcodes from each IMAGE file." << endl
<< endl
<< "Options:" << endl
<< " (-h|--hybrid) use the hybrid binarizer (default)" << endl
<< " (-g|--global) use the global binarizer" << endl
<< " (-v|--verbose) chattier results printing" << endl
<< " --more display more information about the barcode" << endl
<< " --test-mode compare IMAGEs against text files" << endl
<< " --try-harder spend more time to try to find a barcode" << endl
<< " --search-multi search for more than one bar code" << endl
<< endl
<< "Example usage:" << endl
<< " zxing --test-mode *.jpg" << endl
<< endl;
return 1;
}
int total = 0;
int gonly = 0;
int honly = 0;
int both = 0;
int neither = 0;
for (int i = 1; i < argc; i++) {
string filename = argv[i];
if (filename.compare("--verbose") == 0 ||
filename.compare("-v") == 0) {
verbose = true;
continue;
}
if (filename.compare("--hybrid") == 0 ||
filename.compare("-h") == 0) {
use_hybrid = true;
continue;
}
if (filename.compare("--global") == 0 ||
filename.compare("-g") == 0) {
use_global = true;
continue;
}
if (filename.compare("--more") == 0) {
more = true;
continue;
}
if (filename.compare("--test-mode") == 0) {
test_mode = true;
continue;
}
if (filename.compare("--try-harder") == 0) {
try_harder = true;
continue;
}
if (filename.compare("--search-multi") == 0){
search_multi = true;
continue;
}
if (filename.length() > 3 &&
(filename.substr(filename.length() - 3, 3).compare("txt") == 0 ||
filename.substr(filename.length() - 3, 3).compare("bin") == 0)) {
continue;
}
if (!use_global && !use_hybrid) {
use_global = use_hybrid = true;
}
if (test_mode) {
cerr << "Testing: " << filename << endl;
}
Ref<LuminanceSource> source;
try {
source = ImageReaderSource::create(filename);
} catch (const zxing::IllegalArgumentException &e) {
cerr << e.what() << " (ignoring)" << endl;
continue;
}
string expected = read_expected(filename);
int gresult = 1;
int hresult = 1;
if (use_hybrid) {
hresult = read_image(source, true, expected);
}
if (use_global && (verbose || hresult != 0)) {
gresult = read_image(source, false, expected);
if (!verbose && gresult != 0) {
cout << "decoding failed" << endl;
}
}
gresult = gresult == 0;
hresult = hresult == 0;
gonly += gresult && !hresult;
honly += hresult && !gresult;
both += gresult && hresult;
neither += !gresult && !hresult;
total = total + 1;
}
if (test_mode) {
cout << endl
<< "Summary:" << endl
<< " " << total << " images tested total," << endl
<< " " << (honly + both) << " passed hybrid, " << (gonly + both)
<< " passed global, " << both << " pass both, " << endl
<< " " << honly << " passed only hybrid, " << gonly
<< " passed only global, " << neither << " pass neither." << endl;
}
return 0;
}