comparison mupdf-source/thirdparty/zxing-cpp/example/ZXingWriter.cpp @ 2:b50eed0cc0ef upstream

ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4. The directory name has changed: no version number in the expanded directory now.
author Franz Glasner <fzglas.hg@dom66.de>
date Mon, 15 Sep 2025 11:43:07 +0200
parents
children
comparison
equal deleted inserted replaced
1:1d09e1dec1d9 2:b50eed0cc0ef
1 /*
2 * Copyright 2016 Nu-book Inc.
3 */
4 // SPDX-License-Identifier: Apache-2.0
5
6 #ifdef ZXING_EXPERIMENTAL_API
7 #include "WriteBarcode.h"
8 #else
9 #include "BitMatrix.h"
10 #include "BitMatrixIO.h"
11 #include "CharacterSet.h"
12 #include "MultiFormatWriter.h"
13 #endif
14 #include "Version.h"
15
16 #include <algorithm>
17 #include <cctype>
18 #include <cstring>
19 #include <fstream>
20 #include <iostream>
21 #include <string>
22
23 #define STB_IMAGE_WRITE_IMPLEMENTATION
24 #include <stb_image_write.h>
25
26 using namespace ZXing;
27
28 static void PrintUsage(const char* exePath)
29 {
30 std::cout << "Usage: " << exePath
31 << " [-size <width/height>] [-eclevel <level>] [-noqz] [-hrt] <format> <text> <output>\n"
32 << " -size Size of generated image\n"
33 // << " -margin Margin around barcode\n"
34 // << " -encoding Encoding used to encode input text\n"
35 << " -eclevel Error correction level, [0-8]\n"
36 << " -binary Interpret <text> as a file name containing binary data\n"
37 << " -noqz Print barcode witout quiet zone\n"
38 << " -hrt Print human readable text below the barcode (if supported)\n"
39 << " -help Print usage information\n"
40 << " -version Print version information\n"
41 << "\n"
42 << "Supported formats are:\n";
43 #ifdef ZXING_EXPERIMENTAL_API
44 for (auto f : BarcodeFormats::all())
45 #else
46 for (auto f : BarcodeFormatsFromString("Aztec Codabar Code39 Code93 Code128 DataMatrix EAN8 EAN13 ITF PDF417 QRCode UPCA UPCE"))
47 #endif
48 std::cout << " " << ToString(f) << "\n";
49
50 std::cout << "Format can be lowercase letters, with or without '-'.\n"
51 << "Output format is determined by file name, supported are png, jpg and svg.\n";
52 }
53
54 static bool ParseSize(std::string str, int* width, int* height)
55 {
56 std::transform(str.begin(), str.end(), str.begin(), [](char c) { return (char)std::tolower(c); });
57 auto xPos = str.find('x');
58 if (xPos != std::string::npos) {
59 *width = std::stoi(str.substr(0, xPos));
60 *height = std::stoi(str.substr(xPos + 1));
61 return true;
62 }
63 return false;
64 }
65
66 struct CLI
67 {
68 BarcodeFormat format;
69 int sizeHint = 0;
70 std::string input;
71 std::string outPath;
72 std::string ecLevel;
73 bool inputIsFile = false;
74 bool withHRT = false;
75 bool withQZ = true;
76 bool verbose = false;
77 // CharacterSet encoding = CharacterSet::Unknown;
78 };
79
80 static bool ParseOptions(int argc, char* argv[], CLI& cli)
81 {
82 int nonOptArgCount = 0;
83 for (int i = 1; i < argc; ++i) {
84 auto is = [&](const char* str) { return strncmp(argv[i], str, strlen(argv[i])) == 0; };
85 if (is("-size")) {
86 if (++i == argc)
87 return false;
88 cli.sizeHint = std::stoi(argv[i]);
89 } else if (is("-eclevel")) {
90 if (++i == argc)
91 return false;
92 cli.ecLevel = argv[i];
93 // } else if (is("-margin")) {
94 // if (++i == argc)
95 // return false;
96 // cli.margin = std::stoi(argv[i]);
97 // } else if (is("-encoding")) {
98 // if (++i == argc)
99 // return false;
100 // cli.encoding = CharacterSetFromString(argv[i]);
101 } else if (is("-binary")) {
102 cli.inputIsFile = true;
103 } else if (is("-hrt")) {
104 cli.withHRT = true;
105 } else if (is("-noqz")) {
106 cli.withQZ = false;
107 } else if (is("-verbose")) {
108 cli.verbose = true;
109 } else if (is("-help") || is("--help")) {
110 PrintUsage(argv[0]);
111 exit(0);
112 } else if (is("-version") || is("--version")) {
113 std::cout << "ZXingWriter " << ZXING_VERSION_STR << "\n";
114 exit(0);
115 } else if (nonOptArgCount == 0) {
116 cli.format = BarcodeFormatFromString(argv[i]);
117 if (cli.format == BarcodeFormat::None) {
118 std::cerr << "Unrecognized format: " << argv[i] << std::endl;
119 return false;
120 }
121 ++nonOptArgCount;
122 } else if (nonOptArgCount == 1) {
123 cli.input = argv[i];
124 ++nonOptArgCount;
125 } else if (nonOptArgCount == 2) {
126 cli.outPath = argv[i];
127 ++nonOptArgCount;
128 } else {
129 return false;
130 }
131 }
132
133 return nonOptArgCount == 3;
134 }
135
136 static std::string GetExtension(const std::string& path)
137 {
138 auto fileNameStart = path.find_last_of("/\\");
139 auto fileName = fileNameStart == std::string::npos ? path : path.substr(fileNameStart + 1);
140 auto extStart = fileName.find_last_of('.');
141 auto ext = extStart == std::string::npos ? "" : fileName.substr(extStart + 1);
142 std::transform(ext.begin(), ext.end(), ext.begin(), [](char c) { return std::tolower(c); });
143 return ext;
144 }
145
146 template <typename T = char>
147 std::vector<T> ReadFile(const std::string& fn)
148 {
149 std::basic_ifstream<T> ifs(fn, std::ios::binary);
150 if (!ifs.good())
151 throw std::runtime_error("failed to open/read file " + fn);
152 return ifs ? std::vector(std::istreambuf_iterator<T>(ifs), std::istreambuf_iterator<T>()) : std::vector<T>();
153 };
154
155 int main(int argc, char* argv[])
156 {
157 CLI cli;
158
159 if (!ParseOptions(argc, argv, cli)) {
160 PrintUsage(argv[0]);
161 return -1;
162 }
163
164 try {
165 #ifdef ZXING_EXPERIMENTAL_API
166 auto cOpts = CreatorOptions(cli.format).ecLevel(cli.ecLevel);
167 auto barcode = cli.inputIsFile ? CreateBarcodeFromBytes(ReadFile(cli.input), cOpts) : CreateBarcodeFromText(cli.input, cOpts);
168
169 auto wOpts = WriterOptions().sizeHint(cli.sizeHint).withQuietZones(cli.withQZ).withHRT(cli.withHRT).rotate(0);
170 auto bitmap = WriteBarcodeToImage(barcode, wOpts);
171
172 if (cli.verbose) {
173 std::cout << "Text: \"" << barcode.text() << "\"\n"
174 << "Bytes: " << ToHex(barcode.bytes()) << "\n"
175 << "Format: " << ToString(barcode.format()) << "\n"
176 << "Identifier: " << barcode.symbologyIdentifier() << "\n"
177 << "Content: " << ToString(barcode.contentType()) << "\n"
178 << "HasECI: " << barcode.hasECI() << "\n"
179 << "Position: " << ToString(barcode.position()) << "\n"
180 << "Rotation: " << barcode.orientation() << " deg\n"
181 << "IsMirrored: " << barcode.isMirrored() << "\n"
182 << "IsInverted: " << barcode.isInverted() << "\n"
183 << "ecLevel: " << barcode.ecLevel() << "\n";
184 std::cout << WriteBarcodeToUtf8(barcode);
185 }
186 #else
187 auto writer = MultiFormatWriter(cli.format).setMargin(cli.withQZ ? 10 : 0);
188 if (!cli.ecLevel.empty())
189 writer.setEccLevel(std::stoi(cli.ecLevel));
190
191 BitMatrix matrix;
192 if (cli.inputIsFile) {
193 auto file = ReadFile(cli.input);
194 std::wstring bytes;
195 for (uint8_t c : file)
196 bytes.push_back(c);
197 writer.setEncoding(CharacterSet::BINARY);
198 matrix = writer.encode(bytes, cli.sizeHint, std::clamp(cli.sizeHint / 2, 50, 300));
199 } else {
200 writer.setEncoding(CharacterSet::UTF8);
201 matrix = writer.encode(cli.input, cli.sizeHint, std::clamp(cli.sizeHint / 2, 50, 300));
202 }
203 auto bitmap = ToMatrix<uint8_t>(matrix);
204 #endif
205
206 auto ext = GetExtension(cli.outPath);
207 int success = 0;
208 if (ext == "" || ext == "png") {
209 success = stbi_write_png(cli.outPath.c_str(), bitmap.width(), bitmap.height(), 1, bitmap.data(), 0);
210 } else if (ext == "jpg" || ext == "jpeg") {
211 success = stbi_write_jpg(cli.outPath.c_str(), bitmap.width(), bitmap.height(), 1, bitmap.data(), 0);
212 } else if (ext == "svg") {
213 #ifdef ZXING_EXPERIMENTAL_API
214 success = (std::ofstream(cli.outPath) << WriteBarcodeToSVG(barcode, wOpts)).good();
215 #else
216 success = (std::ofstream(cli.outPath) << ToSVG(matrix)).good();
217 #endif
218 }
219
220 if (!success) {
221 std::cerr << "Failed to write image: " << cli.outPath << std::endl;
222 return -1;
223 }
224 } catch (const std::exception& e) {
225 std::cerr << e.what() << std::endl;
226 return -1;
227 }
228
229 return 0;
230 }