C++用zxing识别二维码

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 
#include 
#include 
using namespace zxing; 

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

//BufferBitmapSource.cpp

#include "parseQR\BufferBitmapSource.h"
#include 
 

 
BufferBitmapSource::BufferBitmapSource(int inWidth, int inHeight, ArrayRef 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 BufferBitmapSource::getRow(int y, ArrayRef 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(getWidth());
	for (int x = 0; x < width; x ++)
	{
		row[x] = buffer[y*width+x]; 
	}
	return row; 
}
 
ArrayRef 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 
#include 

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

  const zxing::ArrayRef image;
  const int comps;

  char convertPixel(const char* pixel) const;

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

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

  zxing::ArrayRef getRow(int y, zxing::ArrayRef row) const;
  zxing::ArrayRef 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 
#include 
#include 
#include 
#include 
#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 image_, int width, int height, int comps_)
    : Super(width, height), image(image_), comps(comps_) {}

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

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

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

/** This is a more efficient implementation. */
zxing::ArrayRef ImageReaderSource::getMatrix() const {
  const char* p = &image[0];
  zxing::ArrayRef 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 
#include 
#include 
#include "parseQR\ImageReaderSource.h"
#include "parseQR\BufferBitmapSource.h"
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#include 
#include 
#include 
#include 
#include 

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 > decode(Ref image, DecodeHints hints) {
	Ref reader(new MultiFormatReader);
	return vector >(1, reader->decode(image, hints));
}

vector > decode_multi(Ref image, DecodeHints hints) {
	MultiFormatReader delegate;
	GenericMultipleBarcodeReader reader(delegate);
	return reader.decodeMultiple(image, hints);
}

int read_image(Ref source, bool hybrid, string expected, string& QRResult) {
	vector > results;
	string cell_result;
	int res = -1;

	try {
		Ref binarizer;
		if (hybrid) {
			binarizer = new HybridBinarizer(source);
		} else {
			binarizer = new GlobalHistogramBinarizer(source);
		}
		DecodeHints hints(DecodeHints::DEFAULT_HINT);
		hints.setTryHarder(try_harder);
		Ref 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<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 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 data((char*)buffer, width*height);
		Ref source (new BufferBitmapSource(width, height, data)); 

		// Turn it into a binary image. 
		Ref binarizer (new GlobalHistogramBinarizer(source)); 
		Ref 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(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;
	
}


你可能感兴趣的:(C++)