Skip to content

Commit 91852c5

Browse files
committed
Writer: implement new experimental API (Create + Write)
This adds two new operations 'create' and 'write' next to the existing 'read'. Each new operation is accompanied by an Options class: * ReadBarcodes(..., ReaderOptions) * CreateBarcodeFromText(..., CreatorOptions) * WriteBarcodeToImage(..., WriterOptions) Background info can be found here: * zxing-cpp#724 * zxing-cpp#739
1 parent 8d7a5a2 commit 91852c5

7 files changed

Lines changed: 363 additions & 55 deletions

File tree

‎CMakeLists.txt‎

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,6 @@ if (BUILD_SHARED_LIBS)
3737
set (CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
3838
endif()
3939

40-
if (NOT CMAKE_CXX_STANDARD)
41-
set (CMAKE_CXX_STANDARD 17)
42-
endif()
43-
if (NOT CMAKE_CXX_EXTENSIONS)
44-
set (CMAKE_CXX_EXTENSIONS OFF)
45-
endif()
46-
4740
if (NOT (BUILD_READERS OR BUILD_WRITERS))
4841
message(FATAL_ERROR "At least one of BUILD_READERS/BUILD_WRITERS must be enabled.")
4942
endif()
@@ -55,6 +48,7 @@ if (BUILD_UNIT_TESTS AND (NOT BUILD_WRITERS OR NOT BUILD_READERS))
5548
endif()
5649

5750
if (BUILD_EXPERIMENTAL_API)
51+
set (CMAKE_CXX_STANDARD 20)
5852
add_definitions (-DZXING_BUILD_EXPERIMENTAL_API)
5953
endif()
6054

@@ -64,6 +58,13 @@ if(NOT BUILD_DEPENDENCIES IN_LIST BUILD_DEPENDENCIES_LIST)
6458
message(FATAL_ERROR "BUILD_DEPENDENCIES must be one of ${BUILD_DEPENDENCIES_LIST}")
6559
endif()
6660

61+
if (NOT CMAKE_CXX_STANDARD)
62+
set (CMAKE_CXX_STANDARD 17)
63+
endif()
64+
if (NOT CMAKE_CXX_EXTENSIONS)
65+
set (CMAKE_CXX_EXTENSIONS OFF)
66+
endif()
67+
6768
add_subdirectory (core)
6869

6970
enable_testing()

‎core/CMakeLists.txt‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,8 @@ if (BUILD_WRITERS)
163163
src/TextEncoder.cpp
164164
src/MultiFormatWriter.h
165165
src/MultiFormatWriter.cpp
166+
$<$<BOOL:${BUILD_EXPERIMENTAL_API}>:src/WriteBarcode.h>
167+
$<$<BOOL:${BUILD_EXPERIMENTAL_API}>:src/WriteBarcode.cpp>
166168
)
167169
endif()
168170

@@ -191,6 +193,7 @@ if (BUILD_READERS)
191193
src/ReaderOptions.h
192194
src/Result.h # [[deprecated]]
193195
src/StructuredAppend.h
196+
$<$<BOOL:${BUILD_EXPERIMENTAL_API}>:${CMAKE_CURRENT_SOURCE_DIR}/src/WriteBarcode.h>
194197
$<$<BOOL:${BUILD_C_API}>:${CMAKE_CURRENT_SOURCE_DIR}/src/ZXingC.h>
195198
)
196199
endif()

‎core/src/Barcode.cpp‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,4 +206,4 @@ Barcodes MergeStructuredAppendSequences(const Barcodes& barcodes)
206206
return res;
207207
}
208208

209-
} // ZXing
209+
} // namespace ZXing

‎core/src/Barcode.h‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,7 @@ class Result
164164
std::string version() const;
165165

166166
#ifdef ZXING_BUILD_EXPERIMENTAL_API
167+
void symbol(BitMatrix&& bits) { _symbol = std::make_shared<BitMatrix>(std::move(bits)); }
167168
const BitMatrix& symbol() const { return *_symbol; }
168169
#endif
169170

‎core/src/WriteBarcode.cpp‎

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
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()).setEccLevel(std::stoi(opts.ecLevel())).setMargin(0);
96+
97+
return CreateBarcode(writer.encode(std::string(contents), 0, IsLinearCode(opts.format()) ? 50 : 0), opts);
98+
}
99+
100+
Barcode CreateBarcodeFromText(std::u8string_view contents, const CreatorOptions& opts)
101+
{
102+
return CreateBarcodeFromText({reinterpret_cast<const char*>(contents.data()), contents.size()}, opts);
103+
}
104+
105+
Barcode CreateBarcodeFromBytes(const void* data, int size, const CreatorOptions& opts)
106+
{
107+
std::wstring bytes;
108+
for (uint8_t c : std::basic_string_view<uint8_t>((uint8_t*)data, size))
109+
bytes.push_back(c);
110+
111+
auto writer = MultiFormatWriter(opts.format()).setEccLevel(std::stoi(opts.ecLevel())).setMargin(0);
112+
writer.setEncoding(CharacterSet::BINARY);
113+
114+
return CreateBarcode(writer.encode(bytes, 0, IsLinearCode(opts.format()) ? 50 : 0), opts);
115+
}
116+
117+
std::string WriteBarcodeToSVG(const Barcode& barcode, [[maybe_unused]] const WriterOptions& opts)
118+
{
119+
return ToSVG(barcode.symbol());
120+
}
121+
122+
Image WriteBarcodeToImage(const Barcode& barcode, [[maybe_unused]] const WriterOptions& opts)
123+
{
124+
auto symbol = Inflate(barcode.symbol().copy(), opts.sizeHint(),
125+
IsLinearCode(barcode.format()) ? std::clamp(opts.sizeHint() / 2, 50, 300) : opts.sizeHint(),
126+
opts.withQuietZones() ? 10 : 0);
127+
auto bitmap = ToMatrix<uint8_t>(symbol);
128+
auto iv = Image(symbol.width(), symbol.height());
129+
std::memcpy(const_cast<uint8_t*>(iv.data()), bitmap.data(), iv.width() * iv.height());
130+
return iv;
131+
}
132+
133+
} // namespace ZXing
134+

‎core/src/WriteBarcode.h‎

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
/*
2+
* Copyright 2022 Axel Waggershauser
3+
*/
4+
// SPDX-License-Identifier: Apache-2.0
5+
6+
#pragma once
7+
8+
#include "Barcode.h"
9+
#include "ImageView.h"
10+
11+
#include <memory>
12+
#include <string_view>
13+
14+
extern "C" struct zint_symbol;
15+
16+
namespace ZXing {
17+
18+
class CreatorOptions
19+
{
20+
struct Data;
21+
22+
std::unique_ptr<Data> d;
23+
24+
friend Barcode CreateBarcode(const void* data, int size, int mode, const CreatorOptions& options);
25+
26+
public:
27+
CreatorOptions(BarcodeFormat format);
28+
29+
~CreatorOptions();
30+
CreatorOptions(CreatorOptions&&);
31+
CreatorOptions& operator=(CreatorOptions&&);
32+
33+
zint_symbol* zint() const;
34+
35+
#define ZX_PROPERTY(TYPE, NAME) \
36+
TYPE NAME() const noexcept; \
37+
CreatorOptions& NAME(TYPE v)&; \
38+
CreatorOptions&& NAME(TYPE v)&&;
39+
40+
ZX_PROPERTY(BarcodeFormat, format)
41+
ZX_PROPERTY(bool, readerInit)
42+
ZX_PROPERTY(bool, forceSquareDataMatrix)
43+
ZX_PROPERTY(std::string, ecLevel)
44+
45+
#undef ZX_PROPERTY
46+
};
47+
48+
/**
49+
* Generate barcode from unicode text
50+
*
51+
* @param contents UTF-8 string to encode into a barcode
52+
* @param options CreatorOptions (including BarcodeFormat)
53+
* @return #Barcode generated barcode
54+
*/
55+
Barcode CreateBarcodeFromText(std::string_view contents, const CreatorOptions& options);
56+
Barcode CreateBarcodeFromText(std::u8string_view contents, const CreatorOptions& options);
57+
58+
/**
59+
* Generate barcode from raw binary data
60+
*
61+
* @param data array of bytes to encode into a barcode
62+
* @param size size of byte array
63+
* @param options CreatorOptions (including BarcodeFormat)
64+
* @return #Barcode generated barcode
65+
*/
66+
Barcode CreateBarcodeFromBytes(const void* data, int size, const CreatorOptions& options);
67+
68+
template <typename R>
69+
requires std::ranges::contiguous_range<R> && std::ranges::sized_range<R> && (sizeof(std::ranges::range_value_t<R>) == 1)
70+
Barcode CreateBarcodeFromBytes(const R& contents, const CreatorOptions& options)
71+
{
72+
return CreateBarcodeFromBytes(std::ranges::data(contents), std::ranges::size(contents), options);
73+
}
74+
75+
// =================================================================================
76+
77+
class WriterOptions
78+
{
79+
struct Data;
80+
81+
std::unique_ptr<Data> d;
82+
83+
public:
84+
WriterOptions();
85+
~WriterOptions();
86+
WriterOptions(WriterOptions&&);
87+
WriterOptions& operator=(WriterOptions&&);
88+
89+
#define ZX_PROPERTY(TYPE, NAME) \
90+
TYPE NAME() const noexcept; \
91+
WriterOptions& NAME(TYPE v)&; \
92+
WriterOptions&& NAME(TYPE v)&&;
93+
94+
ZX_PROPERTY(int, scale)
95+
ZX_PROPERTY(int, sizeHint)
96+
ZX_PROPERTY(int, rotate)
97+
ZX_PROPERTY(bool, withHRT)
98+
ZX_PROPERTY(bool, withQuietZones)
99+
100+
#undef ZX_PROPERTY
101+
};
102+
103+
104+
/**
105+
* Write barcode symbol to SVG
106+
*
107+
* @param barcode Barcode to write
108+
* @param options WriterOptions to parameterize rendering
109+
* @return std::string SVG representation of barcode symbol
110+
*/
111+
std::string WriteBarcodeToSVG(const Barcode& barcode, const WriterOptions& options = {});
112+
113+
/**
114+
* Write barcode symbol to Image (Bitmap)
115+
*
116+
* @param barcode Barcode to write
117+
* @param options WriterOptions to parameterize rendering
118+
* @return Image Bitmap reprentation of barcode symbol
119+
*/
120+
Image WriteBarcodeToImage(const Barcode& barcode, const WriterOptions& options = {});
121+
122+
} // ZXing

0 commit comments

Comments
 (0)