1 /*
2 * Copyright 2016 Nu-book Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 
17 #include "ReadBarcode.h"
18 
19 #include <string>
20 #include <memory>
21 #include <stdexcept>
22 #include <emscripten/bind.h>
23 
24 #define STB_IMAGE_IMPLEMENTATION
25 #include "stb_image.h"
26 
27 struct ReadResult
28 {
29 	std::string format;
30 	std::wstring text;
31 	std::string error;
32 	ZXing::Position position;
33 };
34 
readBarcodeFromImage(int bufferPtr,int bufferLength,bool tryHarder,std::string format)35 ReadResult readBarcodeFromImage(int bufferPtr, int bufferLength, bool tryHarder, std::string format)
36 {
37 	using namespace ZXing;
38 	try {
39 		DecodeHints hints;
40 		hints.setTryHarder(tryHarder);
41 		hints.setTryRotate(tryHarder);
42 		hints.setFormats(BarcodeFormatsFromString(format));
43 
44 		int width, height, channels;
45 		std::unique_ptr<stbi_uc, void (*)(void*)> buffer(
46 			stbi_load_from_memory(reinterpret_cast<const unsigned char*>(bufferPtr), bufferLength, &width, &height,
47 								  &channels, 4),
48 			stbi_image_free);
49 		if (buffer == nullptr) {
50 			return { "", L"", "Error loading image" };
51 		}
52 
53 		auto result = ReadBarcode({buffer.get(), width, height, ImageFormat::RGBX}, hints);
54 		if (result.isValid()) {
55 			return { ToString(result.format()), result.text(), "", result.position() };
56 		}
57 	}
58 	catch (const std::exception& e) {
59 		return { "", L"", e.what() };
60 	}
61 	catch (...) {
62 		return { "", L"", "Unknown error" };
63 	}
64 	return {};
65 }
66 
readBarcodeFromPixmap(int bufferPtr,int imgWidth,int imgHeight,bool tryHarder,std::string format)67 ReadResult readBarcodeFromPixmap(int bufferPtr, int imgWidth, int imgHeight, bool tryHarder, std::string format)
68 {
69 	using namespace ZXing;
70 	try {
71 		DecodeHints hints;
72 		hints.setTryHarder(tryHarder);
73 		hints.setTryRotate(tryHarder);
74 		hints.setFormats(BarcodeFormatsFromString(format));
75 
76 		auto result =
77 			ReadBarcode({reinterpret_cast<uint8_t*>(bufferPtr), imgWidth, imgHeight, ImageFormat::RGBX}, hints);
78 
79 		if (result.isValid()) {
80 			return { ToString(result.format()), result.text(), "", result.position() };
81 		}
82 	}
83 	catch (const std::exception& e) {
84 		return { "", L"", e.what() };
85 	}
86 	catch (...) {
87 		return { "", L"", "Unknown error" };
88 	}
89 	return {};
90 }
91 
EMSCRIPTEN_BINDINGS(BarcodeReader)92 EMSCRIPTEN_BINDINGS(BarcodeReader)
93 {
94 	using namespace emscripten;
95 
96 	value_object<ReadResult>("ReadResult")
97 			.field("format", &ReadResult::format)
98 			.field("text", &ReadResult::text)
99 			.field("error", &ReadResult::error)
100 			.field("position", &ReadResult::position)
101 			;
102 
103 	value_object<ZXing::PointI>("Point")
104 			.field("x", &ZXing::PointI::x)
105 			.field("y", &ZXing::PointI::y)
106 			;
107 
108 	value_object<ZXing::Position>("Position")
109 			.field("topLeft", emscripten::index<0>())
110 			.field("topRight", emscripten::index<1>())
111 			.field("bottomRight", emscripten::index<2>())
112 			.field("bottomLeft", emscripten::index<3>())
113 			;
114 
115 	function("readBarcodeFromImage", &readBarcodeFromImage);
116 	function("readBarcodeFromPixmap", &readBarcodeFromPixmap);
117 
118 	// obsoletes
119 	function("readBarcode", &readBarcodeFromImage);
120 	function("readBarcodeFromPng", &readBarcodeFromImage);
121 }
122