C++用zxing識別二維碼

pengfoo發表於2014-05-14

zxing 可以從github的官方網站上下載下來,這裡提供一個VS 2010編譯zxing的靜態庫工程,編譯時注意一點是:zxing的很多不同的資料夾下含有相同名稱的原始檔,在編譯時應該分別設定這些原始檔的obj檔案輸出到不同的路徑下,否則VS預設會將這些obj檔案輸出到同一個目錄下,從而產生相互覆蓋,編譯期也會給出警告,這樣編譯生成的庫不全,後期連結呼叫時很可能發生連結不到的錯誤。具體可以參考下圖。


我這提供一個可用的zxing編譯成靜態庫的VS 2010的工程。

http://download.csdn.net/detail/kuzuozhou/7346123

參考github上給出的示例程式,我這提供了兩個解碼二維碼的介面,1.接收圖片檔案為引數;2.接收圖片的二進位制資料為引數。

相應的原始檔有:

//BufferBitmapSource.h

#include <zxing/LuminanceSource.h>
#include <stdio.h>
#include <stdlib.h>
using namespace zxing; 

 
class BufferBitmapSource : public LuminanceSource {
private:
	typedef LuminanceSource Super;
  int width, height; 
  ArrayRef<char> buffer; 
 
public:
  BufferBitmapSource(int inWidth, int inHeight, ArrayRef<char> inBuffer); 
  ~BufferBitmapSource(); 
 
  int getWidth() const; 
  int getHeight() const; 
  ArrayRef<char> getRow(int y, ArrayRef<char> row) const; 
  ArrayRef<char> getMatrix() const; 
};

//BufferBitmapSource.cpp

#include "parseQR\BufferBitmapSource.h"
#include <iostream>
 

 
BufferBitmapSource::BufferBitmapSource(int inWidth, int inHeight, ArrayRef<char> inBuffer) :Super(inWidth,inHeight),buffer(inBuffer)
{
	width = inWidth; 
	height = inHeight; 
	buffer = inBuffer; 
}
 
BufferBitmapSource::~BufferBitmapSource()
{
}
 
int BufferBitmapSource::getWidth() const
{
	return width; 
}
 
int BufferBitmapSource::getHeight() const
{
	return height; 
}
 
ArrayRef<char> BufferBitmapSource::getRow(int y, ArrayRef<char> row) const
{
	if (y < 0 || y >= height) 
	{
		fprintf(stderr, "ERROR, attempted to read row %d of a %d height image.\n", y, height); 
		return NULL; 
	}
	// WARNING: NO ERROR CHECKING! You will want to add some in your code. 
	if (row == NULL) row = ArrayRef<char>(getWidth());
	for (int x = 0; x < width; x ++)
	{
		row[x] = buffer[y*width+x]; 
	}
	return row; 
}
 
ArrayRef<char> BufferBitmapSource::getMatrix() const
{
	return buffer; 
}
 
//ImageReaderSource.h

// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-
#ifndef __IMAGE_READER_SOURCE_H_
#define __IMAGE_READER_SOURCE_H_
/*
 *  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 <zxing/LuminanceSource.h>
#include <zxing/common/Array.h>

class ImageReaderSource : public zxing::LuminanceSource {
private:
  typedef LuminanceSource Super;

  const zxing::ArrayRef<char> image;
  const int comps;

  char convertPixel(const char* pixel) const;

public:
  static zxing::Ref<LuminanceSource> create(std::string const& filename);

  ImageReaderSource(zxing::ArrayRef<char> image, int width, int height, int comps);

  zxing::ArrayRef<char> getRow(int y, zxing::ArrayRef<char> row) const;
  zxing::ArrayRef<char> getMatrix() const;
};

#endif /* __IMAGE_READER_SOURCE_H_ */

//ImageReaderSource.cpp

/*
 *  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 "parseQR\ImageReaderSource.h"
#include <zxing/common/IllegalArgumentException.h>
#include <iostream>
#include <sstream>
#include <cstdlib>
#include <algorithm>
#include "parseQR\lodepng.h"
#include "parseQR\jpgd.h"

using std::string;
using std::ostringstream;
using zxing::Ref;
using zxing::ArrayRef;
using zxing::LuminanceSource;

inline char ImageReaderSource::convertPixel(char const* pixel_) const {
  unsigned char const* pixel = (unsigned char const*)pixel_;
  if (comps == 1 || comps == 2) {
    // Gray or gray+alpha
    return pixel[0];
  } if (comps == 3 || comps == 4) {
    // Red, Green, Blue, (Alpha)
    // We assume 16 bit values here
    // 0x200 = 1<<9, half an lsb of the result to force rounding
    return (char)((306 * (int)pixel[0] + 601 * (int)pixel[1] +
        117 * (int)pixel[2] + 0x200) >> 10);
  } else {
    throw zxing::IllegalArgumentException("Unexpected image depth");
  }
}

ImageReaderSource::ImageReaderSource(ArrayRef<char> image_, int width, int height, int comps_)
    : Super(width, height), image(image_), comps(comps_) {}

Ref<LuminanceSource> ImageReaderSource::create(string const& filename) {
  string extension = filename.substr(filename.find_last_of(".") + 1);
  std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower);
  int width, height;
  int comps = 0;
  zxing::ArrayRef<char> image;
  if (extension == "png") {
    std::vector<unsigned char> out;

    { unsigned w, h;
      unsigned error = lodepng::decode(out, w, h, filename);
      if (error) {
        ostringstream msg;
        msg << "Error while loading '" << lodepng_error_text(error) << "'";
        throw zxing::IllegalArgumentException(msg.str().c_str());
      }
      width = w;
      height = h;
    }

    comps = 4;
    image = zxing::ArrayRef<char>(4 * width * height);
    memcpy(&image[0], &out[0], image->size());
  } else if (extension == "jpg" || extension == "jpeg") {
    char *buffer = reinterpret_cast<char*>(jpgd::decompress_jpeg_image_from_file(
        filename.c_str(), &width, &height, &comps, 4));
    image = zxing::ArrayRef<char>(buffer, 4 * width * height);
  }
  if (!image) {
    ostringstream msg;
    msg << "Loading \"" << filename << "\" failed.";
    throw zxing::IllegalArgumentException(msg.str().c_str());
  }

  return Ref<LuminanceSource>(new ImageReaderSource(image, width, height, comps));
}

zxing::ArrayRef<char> ImageReaderSource::getRow(int y, zxing::ArrayRef<char> row) const {
  const char* pixelRow = &image[0] + y * getWidth() * 4;
  if (!row) {
    row = zxing::ArrayRef<char>(getWidth());
  }
  for (int x = 0; x < getWidth(); x++) {
    row[x] = convertPixel(pixelRow + (x * 4));
  }
  return row;
}

/** This is a more efficient implementation. */
zxing::ArrayRef<char> ImageReaderSource::getMatrix() const {
  const char* p = &image[0];
  zxing::ArrayRef<char> matrix(getWidth() * getHeight());
  char* m = &matrix[0];
  for (int y = 0; y < getHeight(); y++) {
    for (int x = 0; x < getWidth(); x++) {
      *m = convertPixel(p);
      m++;
      p += 4;
    }
  }
  return matrix;
}

還有其他幾個jpd.h,lodepng.h及其對應的cpp檔案都是示例程式給出的,這裡不再新增了。

最後給出parseQRInfo.cpp的程式碼。

// -*- 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 "parseQR\parseQRInfo.h"

#include <iostream>
#include <fstream>
#include <string>
#include "parseQR\ImageReaderSource.h"
#include "parseQR\BufferBitmapSource.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, string& QRResult) {
	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());
		cout<<cell_result <<endl;
		res = -2;
	} catch (const zxing::IllegalArgumentException& e) {
		cell_result = "zxing::IllegalArgumentException: " + string(e.what());
		cout<<cell_result<<endl;
		res = -3;
	} catch (const zxing::Exception& e) {
		cell_result = "zxing::Exception: " + string(e.what());
		cout<<cell_result<<endl;
		res = -4;
	} catch (const std::exception& e) {
		cell_result = "std::exception: " + string(e.what());
		cout<<cell_result<<endl;
		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;
			QRResult = results[i]->getText()->getText();
		}
	}

	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;
}

bool parseQRInfo(string filename,string& QRResult) {
	

	bool flag = false;

	try_harder = true;

	if (!use_global && !use_hybrid) {
		use_global = use_hybrid = true;
	}

	Ref<LuminanceSource> source;
	try {
		source = ImageReaderSource::create(filename);
	} catch (const zxing::IllegalArgumentException &e) {
		cerr << e.what() << " (ignoring)" << endl;
	}

	string expected = read_expected(filename);

	int gresult = 1;
	int hresult = 1;
	if (use_hybrid) {
		hresult = read_image(source, true, expected, QRResult);
		flag = (hresult==0?true:false);
	}
	if (use_global && (verbose || hresult != 0)) {
		gresult = read_image(source, false, expected, QRResult);
		flag = (gresult==0?true:false);
		if (!verbose && gresult != 0) {
			cout << "decoding failed" << endl;
		}
	}
	return flag;

}

bool parseQRInfo(int width,int height,unsigned char* buffer,std::string &QRResult){
	try{
		// Convert the buffer to something that the library understands. 
		ArrayRef<char> data((char*)buffer, width*height);
		Ref<LuminanceSource> source (new BufferBitmapSource(width, height, data)); 

		// Turn it into a binary image. 
		Ref<Binarizer> binarizer (new GlobalHistogramBinarizer(source)); 
		Ref<BinaryBitmap> image(new BinaryBitmap(binarizer));

		// Tell the decoder to try as hard as possible. 
		DecodeHints hints(DecodeHints::DEFAULT_HINT); 
		hints.setTryHarder(true); 

		// Perform the decoding. 
		QRCodeReader reader;
		Ref<Result> result(reader.decode(image, hints));

		// Output the result. 
		cout << result->getText()->getText() << endl;
		QRResult = result->getText()->getText();

	}

	catch (zxing::Exception& e) 
	{
		cerr << "Error: " << e.what() << endl;
		return false;
	}
	return true;
	
}


相關文章