Skip to content

Commit c9ee228

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 c9ee228

File tree

8 files changed

+371
-56
lines changed

8 files changed

+371
-56
lines changed

CMakeLists.txt

+8-7
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()

Package.swift

+2-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ let package = Package(
1515
.target(
1616
name: "ZXingCppCore",
1717
path: "core/src",
18-
publicHeadersPath: "."
18+
publicHeadersPath: ".",
19+
exclude: ["WriteBarcode.h", "WriteBarcode.cpp"]
1920
),
2021
.target(
2122
name: "ZXingCpp",

core/CMakeLists.txt

+3
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

+1-1
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

+1
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

+138
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
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+

core/src/WriteBarcode.h

+122
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)