You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

125 lines
3.8 KiB

/*
* Copyright 2016 Nu-book Inc.
* Copyright 2023 Axel Waggershauser
*/
// SPDX-License-Identifier: Apache-2.0
#include "ReadBarcode.h"
#include "ZXAlgorithms.h"
#include <emscripten/bind.h>
#include <emscripten/val.h>
#include <memory>
#include <stdexcept>
#include <string>
#define STB_IMAGE_IMPLEMENTATION
#include <stb_image.h>
using namespace ZXing;
struct ReadResult
{
std::string format{};
std::string text{};
emscripten::val bytes;
std::string error{};
Position position{};
std::string symbologyIdentifier{};
};
std::vector<ReadResult> readBarcodes(ImageView iv, bool tryHarder, const std::string& format, int maxSymbols)
{
try {
auto opts = ReaderOptions()
.tryHarder(tryHarder)
.tryRotate(tryHarder)
.tryInvert(tryHarder)
.tryDownscale(tryHarder)
.formats(BarcodeFormatsFromString(format))
// .returnErrors(maxSymbols > 1)
.maxNumberOfSymbols(maxSymbols);
auto barcodes = ReadBarcodes(iv, opts);
std::vector<ReadResult> readResults{};
readResults.reserve(barcodes.size());
thread_local const emscripten::val Uint8Array = emscripten::val::global("Uint8Array");
for (auto&& barcode : barcodes) {
const auto& bytes = barcode.bytes();
readResults.push_back({
ToString(barcode.format()),
barcode.text(),
Uint8Array.new_(emscripten::typed_memory_view(bytes.size(), bytes.data())),
ToString(barcode.error()),
barcode.position(),
barcode.symbologyIdentifier()
});
}
return readResults;
} catch (const std::exception& e) {
return {{"", "", {}, e.what()}};
} catch (...) {
return {{"", "", {}, "Unknown error"}};
}
return {};
}
std::vector<ReadResult> readBarcodesFromImage(int bufferPtr, int bufferLength, bool tryHarder, std::string format, int maxSymbols)
{
int width, height, channels;
std::unique_ptr<stbi_uc, void (*)(void*)> buffer(
stbi_load_from_memory(reinterpret_cast<const unsigned char*>(bufferPtr), bufferLength, &width, &height, &channels, 1),
stbi_image_free);
if (buffer == nullptr)
return {{"", "", {}, "Error loading image"}};
return readBarcodes({buffer.get(), width, height, ImageFormat::Lum}, tryHarder, format, maxSymbols);
}
ReadResult readBarcodeFromImage(int bufferPtr, int bufferLength, bool tryHarder, std::string format)
{
return FirstOrDefault(readBarcodesFromImage(bufferPtr, bufferLength, tryHarder, format, 1));
}
std::vector<ReadResult> readBarcodesFromPixmap(int bufferPtr, int imgWidth, int imgHeight, bool tryHarder, std::string format, int maxSymbols)
{
return readBarcodes({reinterpret_cast<uint8_t*>(bufferPtr), imgWidth, imgHeight, ImageFormat::RGBA}, tryHarder, format, maxSymbols);
}
ReadResult readBarcodeFromPixmap(int bufferPtr, int imgWidth, int imgHeight, bool tryHarder, std::string format)
{
return FirstOrDefault(readBarcodesFromPixmap(bufferPtr, imgWidth, imgHeight, tryHarder, format, 1));
}
EMSCRIPTEN_BINDINGS(BarcodeReader)
{
using namespace emscripten;
value_object<ReadResult>("ReadResult")
.field("format", &ReadResult::format)
.field("text", &ReadResult::text)
.field("bytes", &ReadResult::bytes)
.field("error", &ReadResult::error)
.field("position", &ReadResult::position)
.field("symbologyIdentifier", &ReadResult::symbologyIdentifier);
value_object<ZXing::PointI>("Point").field("x", &ZXing::PointI::x).field("y", &ZXing::PointI::y);
value_object<ZXing::Position>("Position")
.field("topLeft", emscripten::index<0>())
.field("topRight", emscripten::index<1>())
.field("bottomRight", emscripten::index<2>())
.field("bottomLeft", emscripten::index<3>());
register_vector<ReadResult>("vector<ReadResult>");
function("readBarcodeFromImage", &readBarcodeFromImage);
function("readBarcodeFromPixmap", &readBarcodeFromPixmap);
function("readBarcodesFromImage", &readBarcodesFromImage);
function("readBarcodesFromPixmap", &readBarcodesFromPixmap);
};