|
| 1 | +/* |
| 2 | +* Copyright 2024 Axel Waggershauser |
| 3 | +*/ |
| 4 | +// SPDX-License-Identifier: Apache-2.0 |
| 5 | + |
| 6 | +#include "WriteBarcode.h" |
| 7 | + |
| 8 | +struct zint_symbol {}; |
| 9 | + |
| 10 | +namespace ZXing { |
| 11 | + |
| 12 | +struct CreatorOptions::Data |
| 13 | +{ |
| 14 | + BarcodeFormat format; |
| 15 | + bool readerInit = false; |
| 16 | + bool forceSquareDataMatrix = false; |
| 17 | + std::string ecLevel; |
| 18 | + |
| 19 | + // symbol size (qrcode, datamatrix, etc), map from I, 'WxH' |
| 20 | + // structured_append (idx, cnt, ID) |
| 21 | + |
| 22 | + mutable std::unique_ptr<zint_symbol> zint; |
| 23 | +}; |
| 24 | + |
| 25 | +#define ZX_PROPERTY(TYPE, NAME) \ |
| 26 | + TYPE CreatorOptions::NAME() const noexcept { return d->NAME; } \ |
| 27 | + CreatorOptions& CreatorOptions::NAME(TYPE v)& { return d->NAME = std::move(v), *this; } \ |
| 28 | + CreatorOptions&& CreatorOptions::NAME(TYPE v)&& { return d->NAME = std::move(v), std::move(*this); } |
| 29 | + |
| 30 | + ZX_PROPERTY(BarcodeFormat, format) |
| 31 | + ZX_PROPERTY(bool, readerInit) |
| 32 | + ZX_PROPERTY(bool, forceSquareDataMatrix) |
| 33 | + ZX_PROPERTY(std::string, ecLevel) |
| 34 | + |
| 35 | +#undef ZX_PROPERTY |
| 36 | + |
| 37 | +CreatorOptions::CreatorOptions(BarcodeFormat format) : d(std::make_unique<Data>(format)) {} |
| 38 | +CreatorOptions::~CreatorOptions() = default; |
| 39 | +CreatorOptions::CreatorOptions(CreatorOptions&&) = default; |
| 40 | +CreatorOptions& CreatorOptions::operator=(CreatorOptions&&) = default; |
| 41 | + |
| 42 | + |
| 43 | +struct WriterOptions::Data |
| 44 | +{ |
| 45 | + int scale = 0; |
| 46 | + int sizeHint = 0; |
| 47 | + int rotate = 0; |
| 48 | + bool withHRT = false; |
| 49 | + bool withQuietZones = true; |
| 50 | +}; |
| 51 | + |
| 52 | +#define ZX_PROPERTY(TYPE, NAME) \ |
| 53 | + TYPE WriterOptions::NAME() const noexcept { return d->NAME; } \ |
| 54 | + WriterOptions& WriterOptions::NAME(TYPE v)& { return d->NAME = std::move(v), *this; } \ |
| 55 | + WriterOptions&& WriterOptions::NAME(TYPE v)&& { return d->NAME = std::move(v), std::move(*this); } |
| 56 | + |
| 57 | +ZX_PROPERTY(int, scale) |
| 58 | +ZX_PROPERTY(int, sizeHint) |
| 59 | +ZX_PROPERTY(int, rotate) |
| 60 | +ZX_PROPERTY(bool, withHRT) |
| 61 | +ZX_PROPERTY(bool, withQuietZones) |
| 62 | + |
| 63 | +#undef ZX_PROPERTY |
| 64 | + |
| 65 | +WriterOptions::WriterOptions() : d(std::make_unique<Data>()) {} |
| 66 | +WriterOptions::~WriterOptions() = default; |
| 67 | +WriterOptions::WriterOptions(WriterOptions&&) = default; |
| 68 | +WriterOptions& WriterOptions::operator=(WriterOptions&&) = default; |
| 69 | + |
| 70 | +} // namespace ZXing |
| 71 | + |
| 72 | + |
| 73 | +#include "BitMatrix.h" |
| 74 | +#include "MultiFormatWriter.h" |
| 75 | + |
| 76 | +namespace ZXing { |
| 77 | + |
| 78 | +static Barcode CreateBarcode(BitMatrix&& bits, const CreatorOptions& opts) |
| 79 | +{ |
| 80 | + auto img = ToMatrix<uint8_t>(bits); |
| 81 | + |
| 82 | + auto res = ReadBarcode({img.data(), img.width(), img.height(), ImageFormat::Lum}, |
| 83 | + ReaderOptions().setFormats(opts.format()).setIsPure(true).setBinarizer(Binarizer::BoolCast)); |
| 84 | + res.symbol(std::move(bits)); |
| 85 | + return res; |
| 86 | +} |
| 87 | + |
| 88 | +static bool IsLinearCode(BarcodeFormat format) |
| 89 | +{ |
| 90 | + return BarcodeFormats(BarcodeFormat::LinearCodes).testFlag(format); |
| 91 | +} |
| 92 | + |
| 93 | +Barcode CreateBarcodeFromText(std::string_view contents, const CreatorOptions& opts) |
| 94 | +{ |
| 95 | + auto writer = MultiFormatWriter(opts.format()).setMargin(0); |
| 96 | + if (!opts.ecLevel().empty()) |
| 97 | + writer.setEccLevel(std::stoi(opts.ecLevel())); |
| 98 | + |
| 99 | + return CreateBarcode(writer.encode(std::string(contents), 0, IsLinearCode(opts.format()) ? 50 : 0), opts); |
| 100 | +} |
| 101 | + |
| 102 | +Barcode CreateBarcodeFromText(std::u8string_view contents, const CreatorOptions& opts) |
| 103 | +{ |
| 104 | + return CreateBarcodeFromText({reinterpret_cast<const char*>(contents.data()), contents.size()}, opts); |
| 105 | +} |
| 106 | + |
| 107 | +Barcode CreateBarcodeFromBytes(const void* data, int size, const CreatorOptions& opts) |
| 108 | +{ |
| 109 | + std::wstring bytes; |
| 110 | + for (uint8_t c : std::basic_string_view<uint8_t>((uint8_t*)data, size)) |
| 111 | + bytes.push_back(c); |
| 112 | + |
| 113 | + auto writer = MultiFormatWriter(opts.format()).setMargin(0); |
| 114 | + if (!opts.ecLevel().empty()) |
| 115 | + writer.setEccLevel(std::stoi(opts.ecLevel())); |
| 116 | + writer.setEncoding(CharacterSet::BINARY); |
| 117 | + |
| 118 | + return CreateBarcode(writer.encode(bytes, 0, IsLinearCode(opts.format()) ? 50 : 0), opts); |
| 119 | +} |
| 120 | + |
| 121 | +std::string WriteBarcodeToSVG(const Barcode& barcode, [[maybe_unused]] const WriterOptions& opts) |
| 122 | +{ |
| 123 | + return ToSVG(barcode.symbol()); |
| 124 | +} |
| 125 | + |
| 126 | +Image WriteBarcodeToImage(const Barcode& barcode, [[maybe_unused]] const WriterOptions& opts) |
| 127 | +{ |
| 128 | + auto symbol = Inflate(barcode.symbol().copy(), opts.sizeHint(), |
| 129 | + IsLinearCode(barcode.format()) ? std::clamp(opts.sizeHint() / 2, 50, 300) : opts.sizeHint(), |
| 130 | + opts.withQuietZones() ? 10 : 0); |
| 131 | + auto bitmap = ToMatrix<uint8_t>(symbol); |
| 132 | + auto iv = Image(symbol.width(), symbol.height()); |
| 133 | + std::memcpy(const_cast<uint8_t*>(iv.data()), bitmap.data(), iv.width() * iv.height()); |
| 134 | + return iv; |
| 135 | +} |
| 136 | + |
| 137 | +} // namespace ZXing |
| 138 | + |
0 commit comments